fix(ui/alerts): align ALERT_VARIABLES registry with NotificationContextBuilder
Plan prose had spec §8 idealized leaves, but the backend NotificationContext
only emits a subset:
ROUTE_METRIC / EXCHANGE_MATCH → route.id + route.uri (uri added)
LOG_PATTERN → log.pattern + log.matchCount (renamed from log.logger/level/message)
app.slug / app.id → scoped to non-env kinds (removed from 'always')
exchange.link / alert.comparator / alert.window / app.displayName → removed (backend doesn't emit)
Without this alignment the Task 11 linter would (1) flag valid route.uri as
unknown, (2) suggest log.{logger,level,message} as valid paths that render
empty, and (3) flag app.slug on env-wide rules.
This commit is contained in:
@@ -10,18 +10,24 @@ describe('availableVariables', () => {
|
||||
const vars = availableVariables(undefined);
|
||||
expect(vars.find((v) => v.path === 'env.slug')).toBeTruthy();
|
||||
expect(vars.find((v) => v.path === 'exchange.id')).toBeUndefined();
|
||||
expect(vars.find((v) => v.path === 'log.logger')).toBeUndefined();
|
||||
expect(vars.find((v) => v.path === 'log.pattern')).toBeUndefined();
|
||||
expect(vars.find((v) => v.path === 'app.slug')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('adds exchange.* for EXCHANGE_MATCH kind', () => {
|
||||
it('adds exchange.* + route.* + app.* for EXCHANGE_MATCH kind', () => {
|
||||
const vars = availableVariables('EXCHANGE_MATCH');
|
||||
expect(vars.find((v) => v.path === 'exchange.id')).toBeTruthy();
|
||||
expect(vars.find((v) => v.path === 'log.logger')).toBeUndefined();
|
||||
expect(vars.find((v) => v.path === 'route.uri')).toBeTruthy();
|
||||
expect(vars.find((v) => v.path === 'app.slug')).toBeTruthy();
|
||||
expect(vars.find((v) => v.path === 'log.pattern')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('adds log.* for LOG_PATTERN kind', () => {
|
||||
it('adds log.* + app.* for LOG_PATTERN kind', () => {
|
||||
const vars = availableVariables('LOG_PATTERN');
|
||||
expect(vars.find((v) => v.path === 'log.message')).toBeTruthy();
|
||||
expect(vars.find((v) => v.path === 'log.pattern')).toBeTruthy();
|
||||
expect(vars.find((v) => v.path === 'log.matchCount')).toBeTruthy();
|
||||
expect(vars.find((v) => v.path === 'app.slug')).toBeTruthy();
|
||||
expect(vars.find((v) => v.path === 'exchange.id')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('reduces to env-only when reducedContext=true (connection URL editor)', () => {
|
||||
|
||||
@@ -35,39 +35,50 @@ export const ALERT_VARIABLES: AlertVariable[] = [
|
||||
{ path: 'alert.link', type: 'url', description: 'UI link to this alert', sampleValue: 'https://cameleer.example.com/alerts/inbox/2222...', availableForKinds: 'always' },
|
||||
{ path: 'alert.currentValue', type: 'number', description: 'Observed metric value', sampleValue: '0.12', availableForKinds: 'always', mayBeNull: true },
|
||||
{ path: 'alert.threshold', type: 'number', description: 'Rule threshold', sampleValue: '0.05', availableForKinds: 'always', mayBeNull: true },
|
||||
{ path: 'alert.comparator', type: 'string', description: 'Rule comparator', sampleValue: 'GT', availableForKinds: 'always', mayBeNull: true },
|
||||
{ path: 'alert.window', type: 'string', description: 'Rule window (human)', sampleValue: '5m', availableForKinds: 'always', mayBeNull: true },
|
||||
|
||||
// Scope-ish — still always available when scoped, but "may be null" if env-wide
|
||||
{ path: 'app.slug', type: 'string', description: 'App slug', sampleValue: 'orders', availableForKinds: 'always', mayBeNull: true },
|
||||
{ path: 'app.id', type: 'uuid', description: 'App UUID', sampleValue: '33333333-...', availableForKinds: 'always', mayBeNull: true },
|
||||
{ path: 'app.displayName', type: 'string', description: 'App display name', sampleValue: 'Order API', availableForKinds: 'always', mayBeNull: true },
|
||||
// App subtree — populated on every kind except env-wide rules
|
||||
{ path: 'app.slug', type: 'string', description: 'App slug', sampleValue: 'orders',
|
||||
availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH', 'AGENT_STATE', 'DEPLOYMENT_STATE', 'LOG_PATTERN', 'JVM_METRIC'], mayBeNull: true },
|
||||
{ path: 'app.id', type: 'uuid', description: 'App UUID', sampleValue: '33333333-...',
|
||||
availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH', 'AGENT_STATE', 'DEPLOYMENT_STATE', 'LOG_PATTERN', 'JVM_METRIC'], mayBeNull: true },
|
||||
|
||||
// ROUTE_METRIC
|
||||
{ path: 'route.id', type: 'string', description: 'Route ID', sampleValue: 'route-1', availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH'] },
|
||||
// ROUTE_METRIC + EXCHANGE_MATCH share route.*
|
||||
{ path: 'route.id', type: 'string', description: 'Route ID', sampleValue: 'route-1',
|
||||
availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH'] },
|
||||
{ path: 'route.uri', type: 'string', description: 'Route URI', sampleValue: 'direct:orders',
|
||||
availableForKinds: ['ROUTE_METRIC', 'EXCHANGE_MATCH'] },
|
||||
|
||||
// EXCHANGE_MATCH
|
||||
{ path: 'exchange.id', type: 'string', description: 'Exchange ID', sampleValue: 'exch-ab12', availableForKinds: ['EXCHANGE_MATCH'] },
|
||||
{ path: 'exchange.status', type: 'string', description: 'Exchange status', sampleValue: 'FAILED', availableForKinds: ['EXCHANGE_MATCH'] },
|
||||
{ path: 'exchange.link', type: 'url', description: 'UI link to exchange', sampleValue: '/exchanges/orders/route-1/exch-ab12', availableForKinds: ['EXCHANGE_MATCH'] },
|
||||
{ path: 'exchange.id', type: 'string', description: 'Exchange ID', sampleValue: 'exch-ab12',
|
||||
availableForKinds: ['EXCHANGE_MATCH'] },
|
||||
{ path: 'exchange.status', type: 'string', description: 'Exchange status', sampleValue: 'FAILED',
|
||||
availableForKinds: ['EXCHANGE_MATCH'] },
|
||||
|
||||
// AGENT_STATE
|
||||
{ path: 'agent.id', type: 'string', description: 'Agent instance ID', sampleValue: 'prod-orders-0', availableForKinds: ['AGENT_STATE', 'JVM_METRIC'] },
|
||||
{ path: 'agent.name', type: 'string', description: 'Agent display name', sampleValue: 'orders-0', availableForKinds: ['AGENT_STATE', 'JVM_METRIC'] },
|
||||
{ path: 'agent.state', type: 'string', description: 'Agent state', sampleValue: 'DEAD', availableForKinds: ['AGENT_STATE'] },
|
||||
// AGENT_STATE + JVM_METRIC share agent.id/name; AGENT_STATE adds agent.state
|
||||
{ path: 'agent.id', type: 'string', description: 'Agent instance ID', sampleValue: 'prod-orders-0',
|
||||
availableForKinds: ['AGENT_STATE', 'JVM_METRIC'] },
|
||||
{ path: 'agent.name', type: 'string', description: 'Agent display name', sampleValue: 'orders-0',
|
||||
availableForKinds: ['AGENT_STATE', 'JVM_METRIC'] },
|
||||
{ path: 'agent.state', type: 'string', description: 'Agent state', sampleValue: 'DEAD',
|
||||
availableForKinds: ['AGENT_STATE'] },
|
||||
|
||||
// DEPLOYMENT_STATE
|
||||
{ path: 'deployment.id', type: 'uuid', description: 'Deployment UUID', sampleValue: '44444444-...', availableForKinds: ['DEPLOYMENT_STATE'] },
|
||||
{ path: 'deployment.status', type: 'string', description: 'Deployment status', sampleValue: 'FAILED', availableForKinds: ['DEPLOYMENT_STATE'] },
|
||||
{ path: 'deployment.id', type: 'uuid', description: 'Deployment UUID', sampleValue: '44444444-...',
|
||||
availableForKinds: ['DEPLOYMENT_STATE'] },
|
||||
{ path: 'deployment.status', type: 'string', description: 'Deployment status', sampleValue: 'FAILED',
|
||||
availableForKinds: ['DEPLOYMENT_STATE'] },
|
||||
|
||||
// LOG_PATTERN
|
||||
{ path: 'log.logger', type: 'string', description: 'Logger name', sampleValue: 'com.acme.Api', availableForKinds: ['LOG_PATTERN'] },
|
||||
{ path: 'log.level', type: 'string', description: 'Log level', sampleValue: 'ERROR', availableForKinds: ['LOG_PATTERN'] },
|
||||
{ path: 'log.message', type: 'string', description: 'Log message', sampleValue: 'TimeoutException...', availableForKinds: ['LOG_PATTERN'] },
|
||||
// LOG_PATTERN — leaf names match NotificationContextBuilder (log.pattern + log.matchCount)
|
||||
{ path: 'log.pattern', type: 'string', description: 'Matched log pattern', sampleValue: 'TimeoutException',
|
||||
availableForKinds: ['LOG_PATTERN'] },
|
||||
{ path: 'log.matchCount', type: 'number', description: 'Matches in window', sampleValue: '7',
|
||||
availableForKinds: ['LOG_PATTERN'] },
|
||||
|
||||
// JVM_METRIC
|
||||
{ path: 'metric.name', type: 'string', description: 'Metric name', sampleValue: 'heap_used_percent', availableForKinds: ['JVM_METRIC'] },
|
||||
{ path: 'metric.value', type: 'number', description: 'Metric value', sampleValue: '92.1', availableForKinds: ['JVM_METRIC'] },
|
||||
{ path: 'metric.name', type: 'string', description: 'Metric name', sampleValue: 'heap_used_percent',
|
||||
availableForKinds: ['JVM_METRIC'] },
|
||||
{ path: 'metric.value', type: 'number', description: 'Metric value', sampleValue: '92.1',
|
||||
availableForKinds: ['JVM_METRIC'] },
|
||||
];
|
||||
|
||||
/** Filter variables to those available for the given condition kind.
|
||||
|
||||
Reference in New Issue
Block a user