Files
cameleer-server/ui/src/api/queries/dashboard.ts

173 lines
6.1 KiB
TypeScript
Raw Normal View History

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { config } from '../../config';
import { useAuthStore } from '../../auth/auth-store';
import { useRefreshInterval } from './use-refresh-interval';
function authHeaders() {
const token = useAuthStore.getState().accessToken;
return {
Authorization: `Bearer ${token}`,
'X-Cameleer-Protocol-Version': '1',
};
}
async function fetchJson<T>(path: string, params?: Record<string, string | undefined>): Promise<T> {
const qs = new URLSearchParams();
if (params) {
for (const [k, v] of Object.entries(params)) {
if (v != null) qs.set(k, v);
}
}
const url = `${config.apiBaseUrl}${path}${qs.toString() ? `?${qs}` : ''}`;
const res = await fetch(url, { headers: authHeaders() });
if (!res.ok) throw new Error(`Failed to fetch ${path}`);
return res.json();
}
// ── Timeseries by app (L1 charts) ─────────────────────────────────────
export interface TimeseriesBucket {
time: string;
totalCount: number;
failedCount: number;
avgDurationMs: number;
p99DurationMs: number;
activeCount: number;
}
export interface GroupedTimeseries {
[key: string]: { buckets: TimeseriesBucket[] };
}
export function useTimeseriesByApp(from?: string, to?: string, environment?: string) {
const refetchInterval = useRefreshInterval(30_000);
return useQuery({
feat!: move query/logs/routes/diagram/agent-view endpoints under /environments/{envSlug}/ P3C — the last data/query wave of the taxonomy migration. Every user- facing read endpoint that was keyed on env-as-query-param is now under the env-scoped URL, making env impossible to omit and unambiguous in server-side tenant+env filtering. Server: - SearchController: /api/v1/search/** → /api/v1/environments/{envSlug}/... Endpoints: /executions (GET), /executions/search (POST), /stats, /stats/timeseries, /stats/timeseries/by-app, /stats/timeseries/by-route, /stats/punchcard, /attributes/keys, /errors/top. Env comes from path. - LogQueryController: /api/v1/logs → /api/v1/environments/{envSlug}/logs. - RouteCatalogController: /api/v1/routes/catalog → /api/v1/environments/ {envSlug}/routes. Env filter unconditional (path). - RouteMetricsController: /api/v1/routes/metrics → /api/v1/environments/{envSlug}/routes/metrics (and /metrics/processors). - DiagramRenderController: /{contentHash}/render stays flat (hashes are globally unique). Find-by-route moved to /api/v1/environments/{envSlug}/ apps/{appSlug}/routes/{routeId}/diagram — the old GET /diagrams?... handler is removed. - Agent views split cleanly: - AgentListController (new): /api/v1/environments/{envSlug}/agents - AgentEventsController: /api/v1/environments/{envSlug}/agents/events - AgentMetricsController: /api/v1/environments/{envSlug}/agents/ {agentId}/metrics — now also rejects cross-env agents (404) as a defense-in-depth check, fulfilling B3. Agent self-service endpoints (register/refresh/heartbeat/deregister) remain flat at /api/v1/agents/** — JWT-authoritative. SPA: - queries/agents.ts, agent-metrics.ts, logs.ts, catalog.ts (route metrics only; /catalog stays flat), processor-metrics.ts, executions.ts (attributes/keys, stats, timeseries, search), dashboard.ts (all stats/errors/punchcard), correlation.ts, diagrams.ts (by-route) — all rewritten to env-scoped URLs. - Hooks now either read env from useEnvironmentStore internally or require it as an argument. Query keys include env so switching env invalidates caches. - useAgents/useAgentEvents signature simplified — env is no longer a parameter; it's read from the store. Callers (LayoutShell, AgentHealth, AgentInstance) updated accordingly. - LogTab and useStartupLogs thread env through to useLogs. - envFetch helper introduced in executions.ts for env-prefixed raw fetch until schema.d.ts is regenerated against the new backend. BREAKING CHANGE: All these flat paths are removed: /api/v1/search/**, /api/v1/logs, /api/v1/routes/catalog, /api/v1/routes/metrics (and /processors), /api/v1/diagrams (lookup), /api/v1/agents (list), /api/v1/agents/events-log, /api/v1/agents/{id}/metrics, /api/v1/agent-events. Clients must use the /api/v1/environments/{envSlug}/... equivalents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:48:25 +02:00
queryKey: ['dashboard', 'timeseries-by-app', environment, from, to],
queryFn: () => fetchJson<GroupedTimeseries>(
`/environments/${encodeURIComponent(environment!)}/stats/timeseries/by-app`, {
from, to, buckets: '24',
}),
feat!: move query/logs/routes/diagram/agent-view endpoints under /environments/{envSlug}/ P3C — the last data/query wave of the taxonomy migration. Every user- facing read endpoint that was keyed on env-as-query-param is now under the env-scoped URL, making env impossible to omit and unambiguous in server-side tenant+env filtering. Server: - SearchController: /api/v1/search/** → /api/v1/environments/{envSlug}/... Endpoints: /executions (GET), /executions/search (POST), /stats, /stats/timeseries, /stats/timeseries/by-app, /stats/timeseries/by-route, /stats/punchcard, /attributes/keys, /errors/top. Env comes from path. - LogQueryController: /api/v1/logs → /api/v1/environments/{envSlug}/logs. - RouteCatalogController: /api/v1/routes/catalog → /api/v1/environments/ {envSlug}/routes. Env filter unconditional (path). - RouteMetricsController: /api/v1/routes/metrics → /api/v1/environments/{envSlug}/routes/metrics (and /metrics/processors). - DiagramRenderController: /{contentHash}/render stays flat (hashes are globally unique). Find-by-route moved to /api/v1/environments/{envSlug}/ apps/{appSlug}/routes/{routeId}/diagram — the old GET /diagrams?... handler is removed. - Agent views split cleanly: - AgentListController (new): /api/v1/environments/{envSlug}/agents - AgentEventsController: /api/v1/environments/{envSlug}/agents/events - AgentMetricsController: /api/v1/environments/{envSlug}/agents/ {agentId}/metrics — now also rejects cross-env agents (404) as a defense-in-depth check, fulfilling B3. Agent self-service endpoints (register/refresh/heartbeat/deregister) remain flat at /api/v1/agents/** — JWT-authoritative. SPA: - queries/agents.ts, agent-metrics.ts, logs.ts, catalog.ts (route metrics only; /catalog stays flat), processor-metrics.ts, executions.ts (attributes/keys, stats, timeseries, search), dashboard.ts (all stats/errors/punchcard), correlation.ts, diagrams.ts (by-route) — all rewritten to env-scoped URLs. - Hooks now either read env from useEnvironmentStore internally or require it as an argument. Query keys include env so switching env invalidates caches. - useAgents/useAgentEvents signature simplified — env is no longer a parameter; it's read from the store. Callers (LayoutShell, AgentHealth, AgentInstance) updated accordingly. - LogTab and useStartupLogs thread env through to useLogs. - envFetch helper introduced in executions.ts for env-prefixed raw fetch until schema.d.ts is regenerated against the new backend. BREAKING CHANGE: All these flat paths are removed: /api/v1/search/**, /api/v1/logs, /api/v1/routes/catalog, /api/v1/routes/metrics (and /processors), /api/v1/diagrams (lookup), /api/v1/agents (list), /api/v1/agents/events-log, /api/v1/agents/{id}/metrics, /api/v1/agent-events. Clients must use the /api/v1/environments/{envSlug}/... equivalents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:48:25 +02:00
enabled: !!from && !!environment,
placeholderData: (prev: GroupedTimeseries | undefined) => prev,
refetchInterval,
});
}
// ── Timeseries by route (L2 charts) ───────────────────────────────────
export function useTimeseriesByRoute(from?: string, to?: string, application?: string, environment?: string) {
const refetchInterval = useRefreshInterval(30_000);
return useQuery({
feat!: move query/logs/routes/diagram/agent-view endpoints under /environments/{envSlug}/ P3C — the last data/query wave of the taxonomy migration. Every user- facing read endpoint that was keyed on env-as-query-param is now under the env-scoped URL, making env impossible to omit and unambiguous in server-side tenant+env filtering. Server: - SearchController: /api/v1/search/** → /api/v1/environments/{envSlug}/... Endpoints: /executions (GET), /executions/search (POST), /stats, /stats/timeseries, /stats/timeseries/by-app, /stats/timeseries/by-route, /stats/punchcard, /attributes/keys, /errors/top. Env comes from path. - LogQueryController: /api/v1/logs → /api/v1/environments/{envSlug}/logs. - RouteCatalogController: /api/v1/routes/catalog → /api/v1/environments/ {envSlug}/routes. Env filter unconditional (path). - RouteMetricsController: /api/v1/routes/metrics → /api/v1/environments/{envSlug}/routes/metrics (and /metrics/processors). - DiagramRenderController: /{contentHash}/render stays flat (hashes are globally unique). Find-by-route moved to /api/v1/environments/{envSlug}/ apps/{appSlug}/routes/{routeId}/diagram — the old GET /diagrams?... handler is removed. - Agent views split cleanly: - AgentListController (new): /api/v1/environments/{envSlug}/agents - AgentEventsController: /api/v1/environments/{envSlug}/agents/events - AgentMetricsController: /api/v1/environments/{envSlug}/agents/ {agentId}/metrics — now also rejects cross-env agents (404) as a defense-in-depth check, fulfilling B3. Agent self-service endpoints (register/refresh/heartbeat/deregister) remain flat at /api/v1/agents/** — JWT-authoritative. SPA: - queries/agents.ts, agent-metrics.ts, logs.ts, catalog.ts (route metrics only; /catalog stays flat), processor-metrics.ts, executions.ts (attributes/keys, stats, timeseries, search), dashboard.ts (all stats/errors/punchcard), correlation.ts, diagrams.ts (by-route) — all rewritten to env-scoped URLs. - Hooks now either read env from useEnvironmentStore internally or require it as an argument. Query keys include env so switching env invalidates caches. - useAgents/useAgentEvents signature simplified — env is no longer a parameter; it's read from the store. Callers (LayoutShell, AgentHealth, AgentInstance) updated accordingly. - LogTab and useStartupLogs thread env through to useLogs. - envFetch helper introduced in executions.ts for env-prefixed raw fetch until schema.d.ts is regenerated against the new backend. BREAKING CHANGE: All these flat paths are removed: /api/v1/search/**, /api/v1/logs, /api/v1/routes/catalog, /api/v1/routes/metrics (and /processors), /api/v1/diagrams (lookup), /api/v1/agents (list), /api/v1/agents/events-log, /api/v1/agents/{id}/metrics, /api/v1/agent-events. Clients must use the /api/v1/environments/{envSlug}/... equivalents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:48:25 +02:00
queryKey: ['dashboard', 'timeseries-by-route', environment, from, to, application],
queryFn: () => fetchJson<GroupedTimeseries>(
`/environments/${encodeURIComponent(environment!)}/stats/timeseries/by-route`, {
from, to, application, buckets: '24',
}),
feat!: move query/logs/routes/diagram/agent-view endpoints under /environments/{envSlug}/ P3C — the last data/query wave of the taxonomy migration. Every user- facing read endpoint that was keyed on env-as-query-param is now under the env-scoped URL, making env impossible to omit and unambiguous in server-side tenant+env filtering. Server: - SearchController: /api/v1/search/** → /api/v1/environments/{envSlug}/... Endpoints: /executions (GET), /executions/search (POST), /stats, /stats/timeseries, /stats/timeseries/by-app, /stats/timeseries/by-route, /stats/punchcard, /attributes/keys, /errors/top. Env comes from path. - LogQueryController: /api/v1/logs → /api/v1/environments/{envSlug}/logs. - RouteCatalogController: /api/v1/routes/catalog → /api/v1/environments/ {envSlug}/routes. Env filter unconditional (path). - RouteMetricsController: /api/v1/routes/metrics → /api/v1/environments/{envSlug}/routes/metrics (and /metrics/processors). - DiagramRenderController: /{contentHash}/render stays flat (hashes are globally unique). Find-by-route moved to /api/v1/environments/{envSlug}/ apps/{appSlug}/routes/{routeId}/diagram — the old GET /diagrams?... handler is removed. - Agent views split cleanly: - AgentListController (new): /api/v1/environments/{envSlug}/agents - AgentEventsController: /api/v1/environments/{envSlug}/agents/events - AgentMetricsController: /api/v1/environments/{envSlug}/agents/ {agentId}/metrics — now also rejects cross-env agents (404) as a defense-in-depth check, fulfilling B3. Agent self-service endpoints (register/refresh/heartbeat/deregister) remain flat at /api/v1/agents/** — JWT-authoritative. SPA: - queries/agents.ts, agent-metrics.ts, logs.ts, catalog.ts (route metrics only; /catalog stays flat), processor-metrics.ts, executions.ts (attributes/keys, stats, timeseries, search), dashboard.ts (all stats/errors/punchcard), correlation.ts, diagrams.ts (by-route) — all rewritten to env-scoped URLs. - Hooks now either read env from useEnvironmentStore internally or require it as an argument. Query keys include env so switching env invalidates caches. - useAgents/useAgentEvents signature simplified — env is no longer a parameter; it's read from the store. Callers (LayoutShell, AgentHealth, AgentInstance) updated accordingly. - LogTab and useStartupLogs thread env through to useLogs. - envFetch helper introduced in executions.ts for env-prefixed raw fetch until schema.d.ts is regenerated against the new backend. BREAKING CHANGE: All these flat paths are removed: /api/v1/search/**, /api/v1/logs, /api/v1/routes/catalog, /api/v1/routes/metrics (and /processors), /api/v1/diagrams (lookup), /api/v1/agents (list), /api/v1/agents/events-log, /api/v1/agents/{id}/metrics, /api/v1/agent-events. Clients must use the /api/v1/environments/{envSlug}/... equivalents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:48:25 +02:00
enabled: !!from && !!application && !!environment,
placeholderData: (prev: GroupedTimeseries | undefined) => prev,
refetchInterval,
});
}
// ── Top errors (L2/L3) ────────────────────────────────────────────────
export interface TopError {
errorType: string;
routeId: string | null;
processorId: string | null;
count: number;
velocity: number;
trend: 'accelerating' | 'stable' | 'decelerating';
lastSeen: string;
}
export function useTopErrors(from?: string, to?: string, application?: string, routeId?: string, environment?: string) {
const refetchInterval = useRefreshInterval(10_000);
return useQuery({
feat!: move query/logs/routes/diagram/agent-view endpoints under /environments/{envSlug}/ P3C — the last data/query wave of the taxonomy migration. Every user- facing read endpoint that was keyed on env-as-query-param is now under the env-scoped URL, making env impossible to omit and unambiguous in server-side tenant+env filtering. Server: - SearchController: /api/v1/search/** → /api/v1/environments/{envSlug}/... Endpoints: /executions (GET), /executions/search (POST), /stats, /stats/timeseries, /stats/timeseries/by-app, /stats/timeseries/by-route, /stats/punchcard, /attributes/keys, /errors/top. Env comes from path. - LogQueryController: /api/v1/logs → /api/v1/environments/{envSlug}/logs. - RouteCatalogController: /api/v1/routes/catalog → /api/v1/environments/ {envSlug}/routes. Env filter unconditional (path). - RouteMetricsController: /api/v1/routes/metrics → /api/v1/environments/{envSlug}/routes/metrics (and /metrics/processors). - DiagramRenderController: /{contentHash}/render stays flat (hashes are globally unique). Find-by-route moved to /api/v1/environments/{envSlug}/ apps/{appSlug}/routes/{routeId}/diagram — the old GET /diagrams?... handler is removed. - Agent views split cleanly: - AgentListController (new): /api/v1/environments/{envSlug}/agents - AgentEventsController: /api/v1/environments/{envSlug}/agents/events - AgentMetricsController: /api/v1/environments/{envSlug}/agents/ {agentId}/metrics — now also rejects cross-env agents (404) as a defense-in-depth check, fulfilling B3. Agent self-service endpoints (register/refresh/heartbeat/deregister) remain flat at /api/v1/agents/** — JWT-authoritative. SPA: - queries/agents.ts, agent-metrics.ts, logs.ts, catalog.ts (route metrics only; /catalog stays flat), processor-metrics.ts, executions.ts (attributes/keys, stats, timeseries, search), dashboard.ts (all stats/errors/punchcard), correlation.ts, diagrams.ts (by-route) — all rewritten to env-scoped URLs. - Hooks now either read env from useEnvironmentStore internally or require it as an argument. Query keys include env so switching env invalidates caches. - useAgents/useAgentEvents signature simplified — env is no longer a parameter; it's read from the store. Callers (LayoutShell, AgentHealth, AgentInstance) updated accordingly. - LogTab and useStartupLogs thread env through to useLogs. - envFetch helper introduced in executions.ts for env-prefixed raw fetch until schema.d.ts is regenerated against the new backend. BREAKING CHANGE: All these flat paths are removed: /api/v1/search/**, /api/v1/logs, /api/v1/routes/catalog, /api/v1/routes/metrics (and /processors), /api/v1/diagrams (lookup), /api/v1/agents (list), /api/v1/agents/events-log, /api/v1/agents/{id}/metrics, /api/v1/agent-events. Clients must use the /api/v1/environments/{envSlug}/... equivalents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:48:25 +02:00
queryKey: ['dashboard', 'top-errors', environment, from, to, application, routeId],
queryFn: () => fetchJson<TopError[]>(
`/environments/${encodeURIComponent(environment!)}/errors/top`, {
from, to, application, routeId, limit: '5',
}),
feat!: move query/logs/routes/diagram/agent-view endpoints under /environments/{envSlug}/ P3C — the last data/query wave of the taxonomy migration. Every user- facing read endpoint that was keyed on env-as-query-param is now under the env-scoped URL, making env impossible to omit and unambiguous in server-side tenant+env filtering. Server: - SearchController: /api/v1/search/** → /api/v1/environments/{envSlug}/... Endpoints: /executions (GET), /executions/search (POST), /stats, /stats/timeseries, /stats/timeseries/by-app, /stats/timeseries/by-route, /stats/punchcard, /attributes/keys, /errors/top. Env comes from path. - LogQueryController: /api/v1/logs → /api/v1/environments/{envSlug}/logs. - RouteCatalogController: /api/v1/routes/catalog → /api/v1/environments/ {envSlug}/routes. Env filter unconditional (path). - RouteMetricsController: /api/v1/routes/metrics → /api/v1/environments/{envSlug}/routes/metrics (and /metrics/processors). - DiagramRenderController: /{contentHash}/render stays flat (hashes are globally unique). Find-by-route moved to /api/v1/environments/{envSlug}/ apps/{appSlug}/routes/{routeId}/diagram — the old GET /diagrams?... handler is removed. - Agent views split cleanly: - AgentListController (new): /api/v1/environments/{envSlug}/agents - AgentEventsController: /api/v1/environments/{envSlug}/agents/events - AgentMetricsController: /api/v1/environments/{envSlug}/agents/ {agentId}/metrics — now also rejects cross-env agents (404) as a defense-in-depth check, fulfilling B3. Agent self-service endpoints (register/refresh/heartbeat/deregister) remain flat at /api/v1/agents/** — JWT-authoritative. SPA: - queries/agents.ts, agent-metrics.ts, logs.ts, catalog.ts (route metrics only; /catalog stays flat), processor-metrics.ts, executions.ts (attributes/keys, stats, timeseries, search), dashboard.ts (all stats/errors/punchcard), correlation.ts, diagrams.ts (by-route) — all rewritten to env-scoped URLs. - Hooks now either read env from useEnvironmentStore internally or require it as an argument. Query keys include env so switching env invalidates caches. - useAgents/useAgentEvents signature simplified — env is no longer a parameter; it's read from the store. Callers (LayoutShell, AgentHealth, AgentInstance) updated accordingly. - LogTab and useStartupLogs thread env through to useLogs. - envFetch helper introduced in executions.ts for env-prefixed raw fetch until schema.d.ts is regenerated against the new backend. BREAKING CHANGE: All these flat paths are removed: /api/v1/search/**, /api/v1/logs, /api/v1/routes/catalog, /api/v1/routes/metrics (and /processors), /api/v1/diagrams (lookup), /api/v1/agents (list), /api/v1/agents/events-log, /api/v1/agents/{id}/metrics, /api/v1/agent-events. Clients must use the /api/v1/environments/{envSlug}/... equivalents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:48:25 +02:00
enabled: !!from && !!environment,
placeholderData: (prev: TopError[] | undefined) => prev,
refetchInterval,
});
}
// ── Punchcard (weekday x hour heatmap, rolling 7 days) ────────────────
export interface PunchcardCell {
weekday: number;
hour: number;
totalCount: number;
failedCount: number;
}
export function usePunchcard(application?: string, environment?: string) {
const refetchInterval = useRefreshInterval(60_000);
return useQuery({
feat!: move query/logs/routes/diagram/agent-view endpoints under /environments/{envSlug}/ P3C — the last data/query wave of the taxonomy migration. Every user- facing read endpoint that was keyed on env-as-query-param is now under the env-scoped URL, making env impossible to omit and unambiguous in server-side tenant+env filtering. Server: - SearchController: /api/v1/search/** → /api/v1/environments/{envSlug}/... Endpoints: /executions (GET), /executions/search (POST), /stats, /stats/timeseries, /stats/timeseries/by-app, /stats/timeseries/by-route, /stats/punchcard, /attributes/keys, /errors/top. Env comes from path. - LogQueryController: /api/v1/logs → /api/v1/environments/{envSlug}/logs. - RouteCatalogController: /api/v1/routes/catalog → /api/v1/environments/ {envSlug}/routes. Env filter unconditional (path). - RouteMetricsController: /api/v1/routes/metrics → /api/v1/environments/{envSlug}/routes/metrics (and /metrics/processors). - DiagramRenderController: /{contentHash}/render stays flat (hashes are globally unique). Find-by-route moved to /api/v1/environments/{envSlug}/ apps/{appSlug}/routes/{routeId}/diagram — the old GET /diagrams?... handler is removed. - Agent views split cleanly: - AgentListController (new): /api/v1/environments/{envSlug}/agents - AgentEventsController: /api/v1/environments/{envSlug}/agents/events - AgentMetricsController: /api/v1/environments/{envSlug}/agents/ {agentId}/metrics — now also rejects cross-env agents (404) as a defense-in-depth check, fulfilling B3. Agent self-service endpoints (register/refresh/heartbeat/deregister) remain flat at /api/v1/agents/** — JWT-authoritative. SPA: - queries/agents.ts, agent-metrics.ts, logs.ts, catalog.ts (route metrics only; /catalog stays flat), processor-metrics.ts, executions.ts (attributes/keys, stats, timeseries, search), dashboard.ts (all stats/errors/punchcard), correlation.ts, diagrams.ts (by-route) — all rewritten to env-scoped URLs. - Hooks now either read env from useEnvironmentStore internally or require it as an argument. Query keys include env so switching env invalidates caches. - useAgents/useAgentEvents signature simplified — env is no longer a parameter; it's read from the store. Callers (LayoutShell, AgentHealth, AgentInstance) updated accordingly. - LogTab and useStartupLogs thread env through to useLogs. - envFetch helper introduced in executions.ts for env-prefixed raw fetch until schema.d.ts is regenerated against the new backend. BREAKING CHANGE: All these flat paths are removed: /api/v1/search/**, /api/v1/logs, /api/v1/routes/catalog, /api/v1/routes/metrics (and /processors), /api/v1/diagrams (lookup), /api/v1/agents (list), /api/v1/agents/events-log, /api/v1/agents/{id}/metrics, /api/v1/agent-events. Clients must use the /api/v1/environments/{envSlug}/... equivalents. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:48:25 +02:00
queryKey: ['dashboard', 'punchcard', environment, application],
queryFn: () => fetchJson<PunchcardCell[]>(
`/environments/${encodeURIComponent(environment!)}/stats/punchcard`, { application }),
enabled: !!environment,
placeholderData: (prev: PunchcardCell[] | undefined) => prev ?? [],
refetchInterval,
});
}
// ── App settings ──────────────────────────────────────────────────────
export interface AppSettings {
appId: string;
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
environment: string;
slaThresholdMs: number;
healthErrorWarn: number;
healthErrorCrit: number;
healthSlaWarn: number;
healthSlaCrit: number;
createdAt: string;
updatedAt: string;
}
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
export function useAppSettings(appId?: string, environment?: string) {
return useQuery({
feat!: move config & settings under /api/v1/environments/{envSlug}/... P3A of the taxonomy migration. Env-scoped config and settings endpoints now live under the env-prefixed URL shape, making env a first-class path segment instead of a query param. Agent-authoritative config is split off into a dedicated endpoint so agent env comes from the JWT only — never spoofable via URL. Server: - ApplicationConfigController: @RequestMapping("/api/v1/environments/ {envSlug}"). Handlers use @EnvPath Environment env, appSlug as @PathVariable. Removed the dual-mode resolveEnvironmentForRead — user flow only; agent flow moved to AgentConfigController. - AgentConfigController (new): GET /api/v1/agents/config. Reads instanceId from JWT subject, resolves (app, env) from registry, returns AppConfigResponse. Registry miss → falls back to JWT env claim for environment, but 404s if application cannot be derived (no other source without registry). - AppSettingsController: @RequestMapping("/api/v1/environments/ {envSlug}"). List at /app-settings, per-app at /apps/{appSlug}/ settings. Access class-wide PreAuthorize preserved (ADMIN/OPERATOR). SPA: - commands.ts: useAllApplicationConfigs, useApplicationConfig, useUpdateApplicationConfig, useProcessorRouteMapping, useTestExpression — rewritten URLs to /environments/{env}/apps/ {app}/... shape. environment now required on every call. Query keys include environment so cache is env-scoped. - dashboard.ts: useAppSettings, useAllAppSettings, useUpdateAppSettings rewritten. - TapConfigModal: new required environment prop; callers updated. - RouteDetail, ExchangesPage: thread selectedEnv into test-expression and modal. Config changes in SecurityConfig for the new shape landed earlier in P0.2; no security rule changes needed in this commit. BREAKING CHANGE: /api/v1/config/** and /api/v1/admin/app-settings/** paths removed. Agents must use /api/v1/agents/config instead of GET /api/v1/config/{app}; users must use /api/v1/environments/{env}/ apps/{app}/config and /api/v1/environments/{env}/apps/{app}/settings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:33:25 +02:00
queryKey: ['app-settings', environment, appId],
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
queryFn: () => fetchJson<AppSettings>(
feat!: move config & settings under /api/v1/environments/{envSlug}/... P3A of the taxonomy migration. Env-scoped config and settings endpoints now live under the env-prefixed URL shape, making env a first-class path segment instead of a query param. Agent-authoritative config is split off into a dedicated endpoint so agent env comes from the JWT only — never spoofable via URL. Server: - ApplicationConfigController: @RequestMapping("/api/v1/environments/ {envSlug}"). Handlers use @EnvPath Environment env, appSlug as @PathVariable. Removed the dual-mode resolveEnvironmentForRead — user flow only; agent flow moved to AgentConfigController. - AgentConfigController (new): GET /api/v1/agents/config. Reads instanceId from JWT subject, resolves (app, env) from registry, returns AppConfigResponse. Registry miss → falls back to JWT env claim for environment, but 404s if application cannot be derived (no other source without registry). - AppSettingsController: @RequestMapping("/api/v1/environments/ {envSlug}"). List at /app-settings, per-app at /apps/{appSlug}/ settings. Access class-wide PreAuthorize preserved (ADMIN/OPERATOR). SPA: - commands.ts: useAllApplicationConfigs, useApplicationConfig, useUpdateApplicationConfig, useProcessorRouteMapping, useTestExpression — rewritten URLs to /environments/{env}/apps/ {app}/... shape. environment now required on every call. Query keys include environment so cache is env-scoped. - dashboard.ts: useAppSettings, useAllAppSettings, useUpdateAppSettings rewritten. - TapConfigModal: new required environment prop; callers updated. - RouteDetail, ExchangesPage: thread selectedEnv into test-expression and modal. Config changes in SecurityConfig for the new shape landed earlier in P0.2; no security rule changes needed in this commit. BREAKING CHANGE: /api/v1/config/** and /api/v1/admin/app-settings/** paths removed. Agents must use /api/v1/agents/config instead of GET /api/v1/config/{app}; users must use /api/v1/environments/{env}/ apps/{app}/config and /api/v1/environments/{env}/apps/{app}/settings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:33:25 +02:00
`/environments/${encodeURIComponent(environment!)}/apps/${encodeURIComponent(appId!)}/settings`),
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
enabled: !!appId && !!environment,
staleTime: 60_000,
});
}
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
export function useAllAppSettings(environment?: string) {
return useQuery({
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
queryKey: ['app-settings', 'all', environment],
queryFn: () => fetchJson<AppSettings[]>(
feat!: move config & settings under /api/v1/environments/{envSlug}/... P3A of the taxonomy migration. Env-scoped config and settings endpoints now live under the env-prefixed URL shape, making env a first-class path segment instead of a query param. Agent-authoritative config is split off into a dedicated endpoint so agent env comes from the JWT only — never spoofable via URL. Server: - ApplicationConfigController: @RequestMapping("/api/v1/environments/ {envSlug}"). Handlers use @EnvPath Environment env, appSlug as @PathVariable. Removed the dual-mode resolveEnvironmentForRead — user flow only; agent flow moved to AgentConfigController. - AgentConfigController (new): GET /api/v1/agents/config. Reads instanceId from JWT subject, resolves (app, env) from registry, returns AppConfigResponse. Registry miss → falls back to JWT env claim for environment, but 404s if application cannot be derived (no other source without registry). - AppSettingsController: @RequestMapping("/api/v1/environments/ {envSlug}"). List at /app-settings, per-app at /apps/{appSlug}/ settings. Access class-wide PreAuthorize preserved (ADMIN/OPERATOR). SPA: - commands.ts: useAllApplicationConfigs, useApplicationConfig, useUpdateApplicationConfig, useProcessorRouteMapping, useTestExpression — rewritten URLs to /environments/{env}/apps/ {app}/... shape. environment now required on every call. Query keys include environment so cache is env-scoped. - dashboard.ts: useAppSettings, useAllAppSettings, useUpdateAppSettings rewritten. - TapConfigModal: new required environment prop; callers updated. - RouteDetail, ExchangesPage: thread selectedEnv into test-expression and modal. Config changes in SecurityConfig for the new shape landed earlier in P0.2; no security rule changes needed in this commit. BREAKING CHANGE: /api/v1/config/** and /api/v1/admin/app-settings/** paths removed. Agents must use /api/v1/agents/config instead of GET /api/v1/config/{app}; users must use /api/v1/environments/{env}/ apps/{app}/config and /api/v1/environments/{env}/apps/{app}/settings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:33:25 +02:00
`/environments/${encodeURIComponent(environment!)}/app-settings`),
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
enabled: !!environment,
staleTime: 60_000,
});
}
export function useUpdateAppSettings() {
const queryClient = useQueryClient();
return useMutation({
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
mutationFn: async ({ appId, environment, settings }:
{ appId: string; environment: string; settings: Omit<AppSettings, 'appId' | 'createdAt' | 'updatedAt'> }) => {
const res = await fetch(
feat!: move config & settings under /api/v1/environments/{envSlug}/... P3A of the taxonomy migration. Env-scoped config and settings endpoints now live under the env-prefixed URL shape, making env a first-class path segment instead of a query param. Agent-authoritative config is split off into a dedicated endpoint so agent env comes from the JWT only — never spoofable via URL. Server: - ApplicationConfigController: @RequestMapping("/api/v1/environments/ {envSlug}"). Handlers use @EnvPath Environment env, appSlug as @PathVariable. Removed the dual-mode resolveEnvironmentForRead — user flow only; agent flow moved to AgentConfigController. - AgentConfigController (new): GET /api/v1/agents/config. Reads instanceId from JWT subject, resolves (app, env) from registry, returns AppConfigResponse. Registry miss → falls back to JWT env claim for environment, but 404s if application cannot be derived (no other source without registry). - AppSettingsController: @RequestMapping("/api/v1/environments/ {envSlug}"). List at /app-settings, per-app at /apps/{appSlug}/ settings. Access class-wide PreAuthorize preserved (ADMIN/OPERATOR). SPA: - commands.ts: useAllApplicationConfigs, useApplicationConfig, useUpdateApplicationConfig, useProcessorRouteMapping, useTestExpression — rewritten URLs to /environments/{env}/apps/ {app}/... shape. environment now required on every call. Query keys include environment so cache is env-scoped. - dashboard.ts: useAppSettings, useAllAppSettings, useUpdateAppSettings rewritten. - TapConfigModal: new required environment prop; callers updated. - RouteDetail, ExchangesPage: thread selectedEnv into test-expression and modal. Config changes in SecurityConfig for the new shape landed earlier in P0.2; no security rule changes needed in this commit. BREAKING CHANGE: /api/v1/config/** and /api/v1/admin/app-settings/** paths removed. Agents must use /api/v1/agents/config instead of GET /api/v1/config/{app}; users must use /api/v1/environments/{env}/ apps/{app}/config and /api/v1/environments/{env}/apps/{app}/settings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:33:25 +02:00
`${config.apiBaseUrl}/environments/${encodeURIComponent(environment)}/apps/${encodeURIComponent(appId)}/settings`,
feat!: scope per-app config and settings by environment BREAKING: wipe dev PostgreSQL before deploying — V1 checksum changes. Agents must now send environmentId on registration (400 if missing). Two tables previously keyed on app name alone caused cross-environment data bleed: writing config for (app=X, env=dev) would overwrite the row used by (app=X, env=prod) agents, and agent startup fetches ignored env entirely. - V1 schema: application_config and app_settings are now PK (app, env). - Repositories: env-keyed finders/saves; env is the authoritative column, stamped on the stored JSON so the row agrees with itself. - ApplicationConfigController.getConfig is dual-mode — AGENT role uses JWT env claim (agents cannot spoof env); non-agent callers provide env via ?environment= query param. - AppSettingsController endpoints now require ?environment=. - SensitiveKeysAdminController fan-out iterates (app, env) slices so each env gets its own merged keys. - DiagramController ingestion stamps env on TaggedDiagram; ClickHouse route_diagrams INSERT + findProcessorRouteMapping are env-scoped. - AgentRegistrationController: environmentId is required on register; removed all "default" fallbacks from register/refresh/heartbeat auto-heal. - UI hooks (useApplicationConfig, useProcessorRouteMapping, useAppSettings, useAllAppSettings, useUpdateAppSettings) take env, wired to useEnvironmentStore at all call sites. - New ConfigEnvIsolationIT covers env-isolation for both repositories. Plan in docs/superpowers/plans/2026-04-16-environment-scoping.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 22:25:21 +02:00
{
method: 'PUT',
headers: { ...authHeaders(), 'Content-Type': 'application/json' },
body: JSON.stringify(settings),
});
if (!res.ok) throw new Error('Failed to update app settings');
return res.json();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['app-settings'] });
},
});
}