@juice-js/observability 1.0.1-alpha.14 → 1.0.1-alpha.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -0
  3. package/fesm2022/{juice-js-observability-alert.page-TKwqJT2d.mjs → juice-js-observability-alert.page-nEy5Gc6j.mjs} +2 -2
  4. package/fesm2022/{juice-js-observability-alert.page-TKwqJT2d.mjs.map → juice-js-observability-alert.page-nEy5Gc6j.mjs.map} +1 -1
  5. package/fesm2022/{juice-js-observability-alerts.page-B-2uS9wr.mjs → juice-js-observability-alerts.page-DUXXBanH.mjs} +2 -2
  6. package/fesm2022/{juice-js-observability-alerts.page-B-2uS9wr.mjs.map → juice-js-observability-alerts.page-DUXXBanH.mjs.map} +1 -1
  7. package/fesm2022/{juice-js-observability-logs.page-CZNbTl2Q.mjs → juice-js-observability-logs.page-i76xbJLH.mjs} +2 -2
  8. package/fesm2022/{juice-js-observability-logs.page-CZNbTl2Q.mjs.map → juice-js-observability-logs.page-i76xbJLH.mjs.map} +1 -1
  9. package/fesm2022/{juice-js-observability-metrics.page-DoVED9MT.mjs → juice-js-observability-metrics.page-Cq5S0yGJ.mjs} +2 -2
  10. package/fesm2022/{juice-js-observability-metrics.page-DoVED9MT.mjs.map → juice-js-observability-metrics.page-Cq5S0yGJ.mjs.map} +1 -1
  11. package/fesm2022/{juice-js-observability-overview.page-Cod7-cIy.mjs → juice-js-observability-overview.page-DXZl_fUh.mjs} +2 -2
  12. package/fesm2022/{juice-js-observability-overview.page-Cod7-cIy.mjs.map → juice-js-observability-overview.page-DXZl_fUh.mjs.map} +1 -1
  13. package/fesm2022/{juice-js-observability-resource.page-C8RhUipF.mjs → juice-js-observability-resource.page-CauDE6kK.mjs} +2 -2
  14. package/fesm2022/{juice-js-observability-resource.page-C8RhUipF.mjs.map → juice-js-observability-resource.page-CauDE6kK.mjs.map} +1 -1
  15. package/fesm2022/{juice-js-observability-resources.page-KadGxEAh.mjs → juice-js-observability-resources.page-CukW8vVc.mjs} +2 -2
  16. package/fesm2022/{juice-js-observability-resources.page-KadGxEAh.mjs.map → juice-js-observability-resources.page-CukW8vVc.mjs.map} +1 -1
  17. package/fesm2022/{juice-js-observability-rules.page-DKWvNpu9.mjs → juice-js-observability-rules.page-Crb07uWm.mjs} +2 -2
  18. package/fesm2022/{juice-js-observability-rules.page-DKWvNpu9.mjs.map → juice-js-observability-rules.page-Crb07uWm.mjs.map} +1 -1
  19. package/fesm2022/{juice-js-observability-service.page-_yK0kVYS.mjs → juice-js-observability-service.page-Dt8bN2Ry.mjs} +2 -2
  20. package/fesm2022/{juice-js-observability-service.page-_yK0kVYS.mjs.map → juice-js-observability-service.page-Dt8bN2Ry.mjs.map} +1 -1
  21. package/fesm2022/{juice-js-observability-services.page-BtG8zyiI.mjs → juice-js-observability-services.page-B1huLe_a.mjs} +2 -2
  22. package/fesm2022/{juice-js-observability-services.page-BtG8zyiI.mjs.map → juice-js-observability-services.page-B1huLe_a.mjs.map} +1 -1
  23. package/fesm2022/{juice-js-observability-telemetry-B5jMJYfn.mjs → juice-js-observability-telemetry-BftWSOaQ.mjs} +235 -8
  24. package/fesm2022/juice-js-observability-telemetry-BftWSOaQ.mjs.map +1 -0
  25. package/fesm2022/{juice-js-observability-topology.page-B7aXWOYV.mjs → juice-js-observability-topology.page-aMWEXyMB.mjs} +2 -2
  26. package/fesm2022/{juice-js-observability-topology.page-B7aXWOYV.mjs.map → juice-js-observability-topology.page-aMWEXyMB.mjs.map} +1 -1
  27. package/fesm2022/{juice-js-observability-trace.page-CkLNNnKf.mjs → juice-js-observability-trace.page-DUCWnZL5.mjs} +126 -3
  28. package/fesm2022/juice-js-observability-trace.page-DUCWnZL5.mjs.map +1 -0
  29. package/fesm2022/{juice-js-observability-traces.page-DgvNixIc.mjs → juice-js-observability-traces.page-DXSDdeTH.mjs} +2 -2
  30. package/fesm2022/{juice-js-observability-traces.page-DgvNixIc.mjs.map → juice-js-observability-traces.page-DXSDdeTH.mjs.map} +1 -1
  31. package/fesm2022/juice-js-observability.mjs +13 -13
  32. package/package.json +1 -1
  33. package/styles/_observability.scss +2 -0
  34. package/types/juice-js-observability.d.ts +1 -0
  35. package/fesm2022/juice-js-observability-telemetry-B5jMJYfn.mjs.map +0 -1
  36. package/fesm2022/juice-js-observability-trace.page-CkLNNnKf.mjs.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Creatorflow.io
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -59,6 +59,8 @@ like juice-layout's dark-mode toggle) repaints the charts and the graph.
59
59
  - `auditLink` (optional): a link from a trace to its audit records, shown on the trace page as "Audit records ↗".
60
60
  With `@juice-js/audit` mounted at `/audit`: `auditLink: id => ['/audit/traces', id]`. A string is an external URL.
61
61
  Without it, the trace page shows no link.
62
+ - The trace page's resource usage reads .NET's `System.Runtime` meter (.NET 9+): add `AddMeter("System.Runtime")` to the
63
+ host's `WithMetrics`.
62
64
  - The router needs `bindToComponentInputs: true`. The pages take their route and query parameters as inputs.
63
65
  - The host's bearer-token interceptor (`@juice-js/auth`) must cover `apiBase`. The token carries the `platform_tenant`
64
66
  claim and a platform role (`viewer`, `operator` or `admin`).
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService, LinkPipe } from "./juice-js-observability.mjs";
2
- import { _ as ReasonPipe, a as problemText, d as KeyValueTable, l as ContextBar, m as AgoPipe, u as HealthBadge, x as apiResource } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { S as apiResource, d as HealthBadge, f as KeyValueTable, h as AgoPipe, o as problemText, u as ContextBar, v as ReasonPipe } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject, input, signal } from "@angular/core";
5
5
  import { RouterLink } from "@angular/router";
@@ -401,4 +401,4 @@ i0.ɵɵngDeclareClassMetadata({
401
401
  });
402
402
  export { AlertPage };
403
403
 
404
- //# sourceMappingURL=juice-js-observability-alert.page-TKwqJT2d.mjs.map
404
+ //# sourceMappingURL=juice-js-observability-alert.page-nEy5Gc6j.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"juice-js-observability-alert.page-TKwqJT2d.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/alert.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject, input, signal } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe, ReasonPipe } from '../shared/format';\nimport { ContextBar, HealthBadge, KeyValueTable } from '../shared/ui';\nimport { problemText } from '../shared/telemetry';\n\n/**\n * One alert (Console requirements §14): evidence, lifecycle history, the subject's health and reasons, the way into\n * the investigation, and acknowledgement for operators.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, DatePipe, FormsModule, MatButtonModule, MatFormFieldModule, MatInputModule, MatProgressBarModule,\n ContextBar, HealthBadge, KeyValueTable, AgoPipe, ReasonPipe],\n template: `\n <jc-context-bar>\n <a [routerLink]=\"['alerts'] | jcLink\" [queryParams]=\"ctx.keep()\" class=\"jc-crumb\">Alerts</a><span class=\"jc-crumb-sep\">›</span>\n <h1>{{ detail.value()?.alert?.rule ?? '…' }}</h1>\n </jc-context-bar>\n @if (detail.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (detail.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n @if (detail.value(); as d) {\n <div class=\"jc-summary\">\n <span class=\"jc-badge\" [class.jc-health-unhealthy]=\"d.alert.severity === 'Critical'\" [class.jc-health-degraded]=\"d.alert.severity === 'Warning'\">{{ d.alert.severity }}</span>\n <strong>{{ d.alert.state }}</strong>\n <span>{{ d.alert.subjectKey }}</span>\n @if (d.alert.noData) { <span class=\"jc-muted\">no data at the last evaluation: state kept</span> }\n @if (d.alert.subjectType === 'service' && d.alert.subjectId) {\n <a mat-flat-button [routerLink]=\"['services', d.alert.subjectId] | jcLink\" [queryParams]=\"investigate(d.alert.environment)\">Investigate</a>\n <a mat-stroked-button [routerLink]=\"['services', d.alert.subjectId] | jcLink\" [queryParams]=\"investigate(d.alert.environment, { tab: 'traces', status: 'error' })\">Error traces</a>\n }\n @for (l of d.links; track l.url) { <a mat-button [href]=\"l.url\" target=\"_blank\" rel=\"noopener\">{{ l.title }} ↗</a> }\n </div>\n <div class=\"jc-grid-2\">\n <section class=\"jc-card\"><h2>Evidence</h2><jc-kv [values]=\"d.evidence\" /></section>\n <section class=\"jc-card\">\n <h2>Subject health</h2>\n @for (h of d.subjectHealth; track h.subjectId + h.environment) {\n <p><jc-health [state]=\"h.state\" [stale]=\"h.stale\" /> {{ h.environment }}</p>\n <ul class=\"jc-reasons\">@for (r of h.reasons; track r) { <li>{{ r | reason }}</li> }</ul>\n } @empty { <p class=\"jc-muted\">No health for this subject.</p> }\n </section>\n </div>\n <section class=\"jc-card\">\n <h2>History</h2>\n <table class=\"jc-table\"><tbody>\n @for (t of d.history; track t.at + t.to) {\n <tr><td>{{ t.at | date: 'MMM d, HH:mm:ss' }}</td><td>{{ t.from ?? '—' }} → <strong>{{ t.to }}</strong></td><td>{{ t.reason | reason }}</td><td>{{ t.value ?? '—' }}</td></tr>\n }\n </tbody></table>\n </section>\n <section class=\"jc-card\">\n <h2>Acknowledgement</h2>\n @if (d.alert.acknowledgedAt) {\n <p>By <strong>{{ d.alert.acknowledgedBy }}</strong> {{ d.alert.acknowledgedAt | ago }}@if (d.acknowledgeComment) {: “{{ d.acknowledgeComment }}”}</p>\n } @else if (d.alert.state !== 'Resolved') {\n <form (ngSubmit)=\"acknowledge()\" class=\"jc-filter-form\">\n <mat-form-field subscriptSizing=\"dynamic\" class=\"jc-field-wide\"><mat-label>Comment</mat-label><input matInput name=\"comment\" [(ngModel)]=\"comment\" maxlength=\"1000\"></mat-form-field>\n <button mat-flat-button type=\"submit\" [disabled]=\"sending()\">Acknowledge</button>\n </form>\n @if (ackError()) { <p class=\"jc-error\">{{ ackError() }}</p> }\n } @else { <p class=\"jc-muted\">Resolved without acknowledgement.</p> }\n </section>\n }`,\n})\nexport class AlertPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n readonly id = input.required<string>();\n protected comment = '';\n protected readonly sending = signal(false);\n protected readonly ackError = signal('');\n\n protected readonly detail = apiResource({ params: () => this.id(), stream: ({ params }) => this.api.alert(params) });\n protected readonly error = computed(() => problemText(this.detail.error()));\n\n /** The service page over the alert's environment, from shortly before the breach. */\n investigate(environment: string | null, extra: Record<string, string> = {}) {\n const alert = this.detail.value()?.alert;\n const start = alert?.breachStartedAt ? new Date(alert.breachStartedAt).getTime() - 15 * 60_000 : null;\n const end = alert?.resolvedAt ? new Date(alert.resolvedAt).getTime() + 5 * 60_000 : Date.now();\n const window = start && end - start <= 24 * 3_600_000\n ? { from: new Date(start).toISOString(), to: new Date(end).toISOString(), range: null } : {};\n return this.ctx.keep({ env: environment, ...window, ...extra });\n }\n\n acknowledge() {\n this.sending.set(true);\n this.ackError.set('');\n this.api.acknowledge(this.id(), this.comment).subscribe({\n next: () => { this.sending.set(false); this.detail.reload(); },\n error: e => {\n this.sending.set(false);\n this.ackError.set((e as { status?: number }).status === 403 ? 'Acknowledging needs the operator or admin role.' : problemText(e));\n },\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"juice-js-observability-alert.page-nEy5Gc6j.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/alert.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject, input, signal } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { DatePipe } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe, ReasonPipe } from '../shared/format';\nimport { ContextBar, HealthBadge, KeyValueTable } from '../shared/ui';\nimport { problemText } from '../shared/telemetry';\n\n/**\n * One alert (Console requirements §14): evidence, lifecycle history, the subject's health and reasons, the way into\n * the investigation, and acknowledgement for operators.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, DatePipe, FormsModule, MatButtonModule, MatFormFieldModule, MatInputModule, MatProgressBarModule,\n ContextBar, HealthBadge, KeyValueTable, AgoPipe, ReasonPipe],\n template: `\n <jc-context-bar>\n <a [routerLink]=\"['alerts'] | jcLink\" [queryParams]=\"ctx.keep()\" class=\"jc-crumb\">Alerts</a><span class=\"jc-crumb-sep\">›</span>\n <h1>{{ detail.value()?.alert?.rule ?? '…' }}</h1>\n </jc-context-bar>\n @if (detail.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (detail.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n @if (detail.value(); as d) {\n <div class=\"jc-summary\">\n <span class=\"jc-badge\" [class.jc-health-unhealthy]=\"d.alert.severity === 'Critical'\" [class.jc-health-degraded]=\"d.alert.severity === 'Warning'\">{{ d.alert.severity }}</span>\n <strong>{{ d.alert.state }}</strong>\n <span>{{ d.alert.subjectKey }}</span>\n @if (d.alert.noData) { <span class=\"jc-muted\">no data at the last evaluation: state kept</span> }\n @if (d.alert.subjectType === 'service' && d.alert.subjectId) {\n <a mat-flat-button [routerLink]=\"['services', d.alert.subjectId] | jcLink\" [queryParams]=\"investigate(d.alert.environment)\">Investigate</a>\n <a mat-stroked-button [routerLink]=\"['services', d.alert.subjectId] | jcLink\" [queryParams]=\"investigate(d.alert.environment, { tab: 'traces', status: 'error' })\">Error traces</a>\n }\n @for (l of d.links; track l.url) { <a mat-button [href]=\"l.url\" target=\"_blank\" rel=\"noopener\">{{ l.title }} ↗</a> }\n </div>\n <div class=\"jc-grid-2\">\n <section class=\"jc-card\"><h2>Evidence</h2><jc-kv [values]=\"d.evidence\" /></section>\n <section class=\"jc-card\">\n <h2>Subject health</h2>\n @for (h of d.subjectHealth; track h.subjectId + h.environment) {\n <p><jc-health [state]=\"h.state\" [stale]=\"h.stale\" /> {{ h.environment }}</p>\n <ul class=\"jc-reasons\">@for (r of h.reasons; track r) { <li>{{ r | reason }}</li> }</ul>\n } @empty { <p class=\"jc-muted\">No health for this subject.</p> }\n </section>\n </div>\n <section class=\"jc-card\">\n <h2>History</h2>\n <table class=\"jc-table\"><tbody>\n @for (t of d.history; track t.at + t.to) {\n <tr><td>{{ t.at | date: 'MMM d, HH:mm:ss' }}</td><td>{{ t.from ?? '—' }} → <strong>{{ t.to }}</strong></td><td>{{ t.reason | reason }}</td><td>{{ t.value ?? '—' }}</td></tr>\n }\n </tbody></table>\n </section>\n <section class=\"jc-card\">\n <h2>Acknowledgement</h2>\n @if (d.alert.acknowledgedAt) {\n <p>By <strong>{{ d.alert.acknowledgedBy }}</strong> {{ d.alert.acknowledgedAt | ago }}@if (d.acknowledgeComment) {: “{{ d.acknowledgeComment }}”}</p>\n } @else if (d.alert.state !== 'Resolved') {\n <form (ngSubmit)=\"acknowledge()\" class=\"jc-filter-form\">\n <mat-form-field subscriptSizing=\"dynamic\" class=\"jc-field-wide\"><mat-label>Comment</mat-label><input matInput name=\"comment\" [(ngModel)]=\"comment\" maxlength=\"1000\"></mat-form-field>\n <button mat-flat-button type=\"submit\" [disabled]=\"sending()\">Acknowledge</button>\n </form>\n @if (ackError()) { <p class=\"jc-error\">{{ ackError() }}</p> }\n } @else { <p class=\"jc-muted\">Resolved without acknowledgement.</p> }\n </section>\n }`,\n})\nexport class AlertPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n readonly id = input.required<string>();\n protected comment = '';\n protected readonly sending = signal(false);\n protected readonly ackError = signal('');\n\n protected readonly detail = apiResource({ params: () => this.id(), stream: ({ params }) => this.api.alert(params) });\n protected readonly error = computed(() => problemText(this.detail.error()));\n\n /** The service page over the alert's environment, from shortly before the breach. */\n investigate(environment: string | null, extra: Record<string, string> = {}) {\n const alert = this.detail.value()?.alert;\n const start = alert?.breachStartedAt ? new Date(alert.breachStartedAt).getTime() - 15 * 60_000 : null;\n const end = alert?.resolvedAt ? new Date(alert.resolvedAt).getTime() + 5 * 60_000 : Date.now();\n const window = start && end - start <= 24 * 3_600_000\n ? { from: new Date(start).toISOString(), to: new Date(end).toISOString(), range: null } : {};\n return this.ctx.keep({ env: environment, ...window, ...extra });\n }\n\n acknowledge() {\n this.sending.set(true);\n this.ackError.set('');\n this.api.acknowledge(this.id(), this.comment).subscribe({\n next: () => { this.sending.set(false); this.detail.reload(); },\n error: e => {\n this.sending.set(false);\n this.ackError.set((e as { status?: number }).status === 403 ? 'Acknowledging needs the operator or admin role.' : problemText(e));\n },\n });\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService, LinkPipe } from "./juice-js-observability.mjs";
2
- import { a as problemText, l as ContextBar, m as AgoPipe, o as cursorList } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { h as AgoPipe, o as problemText, s as cursorList, u as ContextBar } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject, input } from "@angular/core";
5
5
  import { RouterLink } from "@angular/router";
@@ -208,4 +208,4 @@ i0.ɵɵngDeclareClassMetadata({
208
208
  });
209
209
  export { AlertsPage };
210
210
 
211
- //# sourceMappingURL=juice-js-observability-alerts.page-B-2uS9wr.mjs.map
211
+ //# sourceMappingURL=juice-js-observability-alerts.page-DUXXBanH.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"juice-js-observability-alerts.page-B-2uS9wr.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/alerts.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe } from '../shared/format';\nimport { ContextBar } from '../shared/ui';\nimport { cursorList } from '../shared/paging';\nimport { problemText } from '../shared/telemetry';\n\n/** Alerts, newest first (Console requirements §14), filtered by state; 100 at a time, with the next on request. */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatButtonModule, MatProgressBarModule, ContextBar, AgoPipe],\n template: `\n <jc-context-bar><h1>Alerts</h1>\n @for (s of states; track s) {\n <a class=\"jc-chip\" [class.jc-selected]=\"s === (state() ?? 'firing')\" [routerLink]=\"['alerts'] | jcLink\" [queryParams]=\"ctx.keep({ state: s })\">{{ s }}</a>\n }\n </jc-context-bar>\n @if (alerts.first.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (alerts.first.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n <table class=\"jc-table\">\n <thead><tr><th>Severity</th><th>Rule</th><th>Subject</th><th>State</th><th>Value</th><th>Fired</th><th>Acknowledged</th></tr></thead>\n <tbody>\n @for (a of alerts.items(); track a.id) {\n <tr>\n <td><span class=\"jc-badge\" [class.jc-health-unhealthy]=\"a.severity === 'Critical'\" [class.jc-health-degraded]=\"a.severity === 'Warning'\">{{ a.severity }}</span></td>\n <td><a [routerLink]=\"['alerts', a.id] | jcLink\" [queryParams]=\"ctx.keep()\">{{ a.rule }}</a></td>\n <td>{{ a.subjectKey }}</td>\n <td>{{ a.state }}@if (a.noData) { <span class=\"jc-muted\" title=\"The last evaluation had too few samples; the state is kept\"> · no data</span> }</td>\n <td>{{ a.lastValue ?? '—' }}</td>\n <td>{{ a.firedAt | ago }}</td>\n <td>{{ a.acknowledgedBy ?? '—' }}</td>\n </tr>\n } @empty { @if (alerts.first.hasValue()) { <tr><td colspan=\"7\" class=\"jc-muted\">No {{ state() ?? 'firing' }} alerts.</td></tr> } }\n </tbody>\n </table>\n @if (alerts.items().length > 0) {\n <div class=\"jc-more\">\n <span class=\"jc-muted\">{{ alerts.items().length }} {{ state() ?? 'firing' }} alert{{ alerts.items().length === 1 ? '' : 's' }}{{ alerts.hasMore() ? ', newest first' : '' }}</span>\n @if (alerts.hasMore()) {\n <button mat-button (click)=\"alerts.more()\" [disabled]=\"alerts.loadingMore()\">{{ alerts.loadingMore() ? 'Loading…' : 'Load more' }}</button>\n }\n @if (alerts.moreError()) { <span class=\"jc-error\">{{ moreError() }}</span> }\n </div>\n }`,\n})\nexport class AlertsPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n protected readonly states = ['firing', 'pending', 'resolved'];\n readonly state = input<string>();\n protected readonly alerts = cursorList(\n () => ({ state: this.state() ?? 'firing', environment: this.ctx.environment() }), params => params, q => this.api.alerts(q));\n protected readonly error = computed(() => problemText(this.alerts.first.error()));\n protected readonly moreError = computed(() => problemText(this.alerts.moreError()));\n}\n"],"mappings":";;;;;;;;;AAkDA,IAAa,aAAb,MAAa,WAAU;CACF,MAAM,OAAO,cAAc;CAC7B,MAAM,OAAO,UAAU;CACrB,SAAS;EAAC;EAAU;EAAW;CAAU;CACnD,QAAQ,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACb,SAAS,kBACnB;EAAE,OAAO,KAAK,MAAK,KAAM;EAAU,aAAa,KAAK,IAAI,YAAW;CAAE,KAAK,WAAU,SAAQ,MAAK,KAAK,IAAI,OAAO,CAAC,CAAC;CAC1G,QAAQ,eAAe,YAAY,KAAK,OAAO,MAAM,MAAK,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAC9D,YAAY,eAAe,YAAY,KAAK,OAAO,UAAS,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CARxE,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAU,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAV,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAU,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,OAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,UAAA;EAAA,UAlCX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCN,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAjCgB;IAAU,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAe;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,WAAA;IAAA,UAAA,CAAA,aAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAoB;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,cAAA;IAAA,UAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAvE;IAAQ,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAiE;IAAO,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAmC/E,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAU,YAAA,CAAA;EArCtB,MAAA;EAAU,MAAA,CAAA;GACT,iBAAiB,wBAAwB;GACzC,SAAS;IAAC;IAAU;IAAY;IAAiB;IAAsB;IAAY;GAAO;GAC1F,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCX,CAAA"}
1
+ {"version":3,"file":"juice-js-observability-alerts.page-DUXXBanH.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/alerts.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe } from '../shared/format';\nimport { ContextBar } from '../shared/ui';\nimport { cursorList } from '../shared/paging';\nimport { problemText } from '../shared/telemetry';\n\n/** Alerts, newest first (Console requirements §14), filtered by state; 100 at a time, with the next on request. */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatButtonModule, MatProgressBarModule, ContextBar, AgoPipe],\n template: `\n <jc-context-bar><h1>Alerts</h1>\n @for (s of states; track s) {\n <a class=\"jc-chip\" [class.jc-selected]=\"s === (state() ?? 'firing')\" [routerLink]=\"['alerts'] | jcLink\" [queryParams]=\"ctx.keep({ state: s })\">{{ s }}</a>\n }\n </jc-context-bar>\n @if (alerts.first.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (alerts.first.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n <table class=\"jc-table\">\n <thead><tr><th>Severity</th><th>Rule</th><th>Subject</th><th>State</th><th>Value</th><th>Fired</th><th>Acknowledged</th></tr></thead>\n <tbody>\n @for (a of alerts.items(); track a.id) {\n <tr>\n <td><span class=\"jc-badge\" [class.jc-health-unhealthy]=\"a.severity === 'Critical'\" [class.jc-health-degraded]=\"a.severity === 'Warning'\">{{ a.severity }}</span></td>\n <td><a [routerLink]=\"['alerts', a.id] | jcLink\" [queryParams]=\"ctx.keep()\">{{ a.rule }}</a></td>\n <td>{{ a.subjectKey }}</td>\n <td>{{ a.state }}@if (a.noData) { <span class=\"jc-muted\" title=\"The last evaluation had too few samples; the state is kept\"> · no data</span> }</td>\n <td>{{ a.lastValue ?? '—' }}</td>\n <td>{{ a.firedAt | ago }}</td>\n <td>{{ a.acknowledgedBy ?? '—' }}</td>\n </tr>\n } @empty { @if (alerts.first.hasValue()) { <tr><td colspan=\"7\" class=\"jc-muted\">No {{ state() ?? 'firing' }} alerts.</td></tr> } }\n </tbody>\n </table>\n @if (alerts.items().length > 0) {\n <div class=\"jc-more\">\n <span class=\"jc-muted\">{{ alerts.items().length }} {{ state() ?? 'firing' }} alert{{ alerts.items().length === 1 ? '' : 's' }}{{ alerts.hasMore() ? ', newest first' : '' }}</span>\n @if (alerts.hasMore()) {\n <button mat-button (click)=\"alerts.more()\" [disabled]=\"alerts.loadingMore()\">{{ alerts.loadingMore() ? 'Loading…' : 'Load more' }}</button>\n }\n @if (alerts.moreError()) { <span class=\"jc-error\">{{ moreError() }}</span> }\n </div>\n }`,\n})\nexport class AlertsPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n protected readonly states = ['firing', 'pending', 'resolved'];\n readonly state = input<string>();\n protected readonly alerts = cursorList(\n () => ({ state: this.state() ?? 'firing', environment: this.ctx.environment() }), params => params, q => this.api.alerts(q));\n protected readonly error = computed(() => problemText(this.alerts.first.error()));\n protected readonly moreError = computed(() => problemText(this.alerts.moreError()));\n}\n"],"mappings":";;;;;;;;;AAkDA,IAAa,aAAb,MAAa,WAAU;CACF,MAAM,OAAO,cAAc;CAC7B,MAAM,OAAO,UAAU;CACrB,SAAS;EAAC;EAAU;EAAW;CAAU;CACnD,QAAQ,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACb,SAAS,kBACnB;EAAE,OAAO,KAAK,MAAK,KAAM;EAAU,aAAa,KAAK,IAAI,YAAW;CAAE,KAAK,WAAU,SAAQ,MAAK,KAAK,IAAI,OAAO,CAAC,CAAC;CAC1G,QAAQ,eAAe,YAAY,KAAK,OAAO,MAAM,MAAK,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAC9D,YAAY,eAAe,YAAY,KAAK,OAAO,UAAS,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CARxE,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAU,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAV,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAU,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,OAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,UAAA;EAAA,UAlCX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCN,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAjCgB;IAAU,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAe;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,WAAA;IAAA,UAAA,CAAA,aAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAoB;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,cAAA;IAAA,UAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAvE;IAAQ,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAiE;IAAO,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAmC/E,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAU,YAAA,CAAA;EArCtB,MAAA;EAAU,MAAA,CAAA;GACT,iBAAiB,wBAAwB;GACzC,SAAS;IAAC;IAAU;IAAY;IAAiB;IAAsB;IAAY;GAAO;GAC1F,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCX,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService } from "./juice-js-observability.mjs";
2
- import { l as ContextBar, t as LogTable, x as apiResource } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { S as apiResource, n as LogTable, u as ContextBar } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject, input } from "@angular/core";
5
5
  import { map } from "rxjs";
@@ -410,4 +410,4 @@ i0.ɵɵngDeclareClassMetadata({
410
410
  });
411
411
  export { LogsPage };
412
412
 
413
- //# sourceMappingURL=juice-js-observability-logs.page-CZNbTl2Q.mjs.map
413
+ //# sourceMappingURL=juice-js-observability-logs.page-i76xbJLH.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"juice-js-observability-logs.page-CZNbTl2Q.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/logs.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatSelectModule } from '@angular/material/select';\nimport { Router } from '@angular/router';\nimport { map } from 'rxjs';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { ContextBar } from '../shared/ui';\nimport { LogTable } from '../shared/telemetry';\n\n/** Log search (Console requirements §7): by service, severity, text, trace or span; each record links to its trace. */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [FormsModule, MatButtonModule, MatFormFieldModule, MatInputModule, MatSelectModule, ContextBar, LogTable],\n template: `\n <jc-context-bar><h1>Logs</h1></jc-context-bar>\n <form class=\"jc-filter-form\" (ngSubmit)=\"apply(f.value)\" #f=\"ngForm\">\n <mat-form-field subscriptSizing=\"dynamic\">\n <mat-label>Service</mat-label>\n <mat-select name=\"service\" [ngModel]=\"service() ?? ''\">\n <mat-option value=\"\">Any</mat-option>\n @for (s of services.value() ?? []; track s.id) { <mat-option [value]=\"s.id\">{{ s.key }}</mat-option> }\n </mat-select>\n </mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"jc-field-sm\">\n <mat-label>Severity at least</mat-label>\n <mat-select name=\"severity\" [ngModel]=\"severity() ?? ''\">\n <mat-option value=\"\">Any</mat-option><mat-option value=\"5\">Debug</mat-option><mat-option value=\"9\">Info</mat-option>\n <mat-option value=\"13\">Warn</mat-option><mat-option value=\"17\">Error</mat-option><mat-option value=\"21\">Fatal</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"jc-field-wide\"><mat-label>Message contains</mat-label><input matInput name=\"q\" [ngModel]=\"q() ?? ''\"></mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\"><mat-label>Trace ID</mat-label><input matInput name=\"trace\" [ngModel]=\"trace() ?? ''\"></mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\"><mat-label>Span ID</mat-label><input matInput name=\"spanId\" [ngModel]=\"spanId() ?? ''\"></mat-form-field>\n <button mat-flat-button type=\"submit\">Search</button>\n <button mat-button type=\"button\" (click)=\"clear()\">Clear</button>\n </form>\n <jc-log-table [query]=\"query()\" />`,\n})\nexport class LogsPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n private readonly router = inject(Router);\n\n readonly service = input<string>();\n readonly severity = input<string>();\n readonly q = input<string>();\n readonly trace = input<string>();\n readonly spanId = input<string>();\n readonly instance = input<string>();\n readonly resource = input<string>();\n\n protected readonly services = apiResource({ stream: () => this.api.resources('service').pipe(map(p => p.items)) });\n protected readonly query = computed(() => ({\n serviceId: this.service(), minSeverity: this.severity(), q: this.q(), traceId: this.trace(), spanId: this.spanId(),\n instanceId: this.instance(), resourceId: this.resource(),\n }));\n\n apply(value: Record<string, unknown>) {\n const queryParams: Record<string, unknown> = {};\n for (const [key, v] of Object.entries(value)) queryParams[key] = v === '' || v === undefined ? null : v;\n void this.router.navigate([], { queryParams, queryParamsHandling: 'merge' });\n }\n\n clear() { void this.router.navigate([], { queryParams: this.ctx.keep() }); }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"juice-js-observability-logs.page-i76xbJLH.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/logs.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatSelectModule } from '@angular/material/select';\nimport { Router } from '@angular/router';\nimport { map } from 'rxjs';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { ContextBar } from '../shared/ui';\nimport { LogTable } from '../shared/telemetry';\n\n/** Log search (Console requirements §7): by service, severity, text, trace or span; each record links to its trace. */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [FormsModule, MatButtonModule, MatFormFieldModule, MatInputModule, MatSelectModule, ContextBar, LogTable],\n template: `\n <jc-context-bar><h1>Logs</h1></jc-context-bar>\n <form class=\"jc-filter-form\" (ngSubmit)=\"apply(f.value)\" #f=\"ngForm\">\n <mat-form-field subscriptSizing=\"dynamic\">\n <mat-label>Service</mat-label>\n <mat-select name=\"service\" [ngModel]=\"service() ?? ''\">\n <mat-option value=\"\">Any</mat-option>\n @for (s of services.value() ?? []; track s.id) { <mat-option [value]=\"s.id\">{{ s.key }}</mat-option> }\n </mat-select>\n </mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"jc-field-sm\">\n <mat-label>Severity at least</mat-label>\n <mat-select name=\"severity\" [ngModel]=\"severity() ?? ''\">\n <mat-option value=\"\">Any</mat-option><mat-option value=\"5\">Debug</mat-option><mat-option value=\"9\">Info</mat-option>\n <mat-option value=\"13\">Warn</mat-option><mat-option value=\"17\">Error</mat-option><mat-option value=\"21\">Fatal</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"jc-field-wide\"><mat-label>Message contains</mat-label><input matInput name=\"q\" [ngModel]=\"q() ?? ''\"></mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\"><mat-label>Trace ID</mat-label><input matInput name=\"trace\" [ngModel]=\"trace() ?? ''\"></mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\"><mat-label>Span ID</mat-label><input matInput name=\"spanId\" [ngModel]=\"spanId() ?? ''\"></mat-form-field>\n <button mat-flat-button type=\"submit\">Search</button>\n <button mat-button type=\"button\" (click)=\"clear()\">Clear</button>\n </form>\n <jc-log-table [query]=\"query()\" />`,\n})\nexport class LogsPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n private readonly router = inject(Router);\n\n readonly service = input<string>();\n readonly severity = input<string>();\n readonly q = input<string>();\n readonly trace = input<string>();\n readonly spanId = input<string>();\n readonly instance = input<string>();\n readonly resource = input<string>();\n\n protected readonly services = apiResource({ stream: () => this.api.resources('service').pipe(map(p => p.items)) });\n protected readonly query = computed(() => ({\n serviceId: this.service(), minSeverity: this.severity(), q: this.q(), traceId: this.trace(), spanId: this.spanId(),\n instanceId: this.instance(), resourceId: this.resource(),\n }));\n\n apply(value: Record<string, unknown>) {\n const queryParams: Record<string, unknown> = {};\n for (const [key, v] of Object.entries(value)) queryParams[key] = v === '' || v === undefined ? null : v;\n void this.router.navigate([], { queryParams, queryParamsHandling: 'merge' });\n }\n\n clear() { void this.router.navigate([], { queryParams: this.ctx.keep() }); }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA2CA,IAAa,WAAb,MAAa,SAAQ;CACA,MAAM,OAAO,cAAc;CAC7B,MAAM,OAAO,UAAU;CACvB,SAAS,OAAO,MAAM;CAE9B,UAAU,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CACzB,WAAW,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAC1B,IAAI,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,IAAA,CAAA,+BAAA,CAAA,CAAA;CACnB,QAAQ,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACvB,SAAS,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACxB,WAAW,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAC1B,WAAW,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEhB,WAAW,YAAY,EAAE,cAAc,KAAK,IAAI,UAAU,SAAS,CAAC,CAAC,KAAK,KAAI,MAAK,EAAE,KAAK,CAAC,EAAC,CAAE;CAC9F,QAAQ,gBAAgB;EACzC,WAAW,KAAK,QAAO;EAAI,aAAa,KAAK,SAAQ;EAAI,GAAG,KAAK,EAAC;EAAI,SAAS,KAAK,MAAK;EAAI,QAAQ,KAAK,OAAM;EAChH,YAAY,KAAK,SAAQ;EAAI,YAAY,KAAK,SAAQ;CACvD,IAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAEH,MAAM,OAA8B;EAClC,MAAM,cAAuC,CAAA;EAC7C,KAAK,MAAM,CAAC,KAAK,MAAM,OAAO,QAAQ,KAAK,GAAG,YAAY,OAAO,MAAM,MAAM,MAAM,SAAY,OAAO;EACtG,AAAK,KAAK,OAAO,SAAS,CAAA,GAAI;GAAE;GAAa,qBAAqB;EAAO,CAAE;CAC7E;CAEA,QAAK;EAAK,AAAK,KAAK,OAAO,SAAS,CAAA,GAAI,EAAE,aAAa,KAAK,IAAI,KAAI,EAAE,CAAE;CAAG;CAzBhE,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAQ,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAR,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAQ,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,GAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,UAAA;EAAA,UAzBT;;;;;;;;;;;;;;;;;;;;;;;;EAuB2B,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAxB3B;GAAW;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,eAAA;IAAA,UAAA,CAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,eAAA;IAAA,SAAA,CAAA,UAAA;IAAA,UAAA,CAAA,QAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAe;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,WAAA;IAAA,UAAA,CAAA,aAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAkB;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,UAAA,CAAA,cAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAc;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,UAAA,CAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAe;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,UAAA,CAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,mBAAA;IAAA,UAAA,CAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAQ,UAAA;IAAA,QAAA,CAAA,SAAA,SAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AA0BtG,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAQ,YAAA,CAAA;EA5BpB,MAAA;EAAU,MAAA,CAAA;GACT,iBAAiB,wBAAwB;GACzC,SAAS;IAAC;IAAa;IAAiB;IAAoB;IAAgB;IAAiB;IAAY;GAAQ;GACjH,UAAU;;;;;;;;;;;;;;;;;;;;;;;;EAwBX,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService } from "./juice-js-observability.mjs";
2
- import { l as ContextBar, n as MetricExplorer, x as apiResource } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { S as apiResource, r as MetricExplorer, u as ContextBar } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject, input } from "@angular/core";
5
5
  import { map } from "rxjs";
@@ -264,4 +264,4 @@ i0.ɵɵngDeclareClassMetadata({
264
264
  });
265
265
  export { MetricsPage };
266
266
 
267
- //# sourceMappingURL=juice-js-observability-metrics.page-DoVED9MT.mjs.map
267
+ //# sourceMappingURL=juice-js-observability-metrics.page-Cq5S0yGJ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"juice-js-observability-metrics.page-DoVED9MT.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/metrics.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { FormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatSelectModule } from '@angular/material/select';\nimport { Router } from '@angular/router';\nimport { map } from 'rxjs';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { ContextBar } from '../shared/ui';\nimport { MetricExplorer } from '../shared/telemetry';\n\n/** Metrics of a service or a host (Console requirements §7): pick a scope, then a metric. */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [FormsModule, MatFormFieldModule, MatSelectModule, ContextBar, MetricExplorer],\n template: `\n <jc-context-bar><h1>Metrics</h1></jc-context-bar>\n <div class=\"jc-filter-form\">\n <mat-form-field subscriptSizing=\"dynamic\">\n <mat-label>Service</mat-label>\n <mat-select [ngModel]=\"service() ?? ''\" (ngModelChange)=\"scope({ service: $event || null, resource: null })\">\n <mat-option value=\"\">Any</mat-option>\n @for (s of services.value() ?? []; track s.id) { <mat-option [value]=\"s.id\">{{ s.key }}</mat-option> }\n </mat-select>\n </mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\">\n <mat-label>Host</mat-label>\n <mat-select [ngModel]=\"resource() ?? ''\" (ngModelChange)=\"scope({ resource: $event || null, service: null })\">\n <mat-option value=\"\">Any</mat-option>\n @for (h of hosts.value() ?? []; track h.id) { <mat-option [value]=\"h.id\">{{ h.displayName }}</mat-option> }\n </mat-select>\n </mat-form-field>\n </div>\n <jc-metric-explorer [scope]=\"query()\" [initial]=\"metric() ?? null\" />`,\n})\nexport class MetricsPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n private readonly router = inject(Router);\n readonly service = input<string>();\n readonly resource = input<string>();\n readonly metric = input<string>();\n\n protected readonly services = apiResource({ stream: () => this.api.resources('service').pipe(map(p => p.items)) });\n protected readonly hosts = apiResource({ stream: () => this.api.resources('host').pipe(map(p => p.items)) });\n protected readonly query = computed(() => ({ serviceId: this.service(), resourceId: this.resource() }));\n\n scope(change: Record<string, string | null>) {\n void this.router.navigate([], { queryParams: change, queryParamsHandling: 'merge' });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"juice-js-observability-metrics.page-Cq5S0yGJ.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/metrics.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { FormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatSelectModule } from '@angular/material/select';\nimport { Router } from '@angular/router';\nimport { map } from 'rxjs';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { ContextBar } from '../shared/ui';\nimport { MetricExplorer } from '../shared/telemetry';\n\n/** Metrics of a service or a host (Console requirements §7): pick a scope, then a metric. */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [FormsModule, MatFormFieldModule, MatSelectModule, ContextBar, MetricExplorer],\n template: `\n <jc-context-bar><h1>Metrics</h1></jc-context-bar>\n <div class=\"jc-filter-form\">\n <mat-form-field subscriptSizing=\"dynamic\">\n <mat-label>Service</mat-label>\n <mat-select [ngModel]=\"service() ?? ''\" (ngModelChange)=\"scope({ service: $event || null, resource: null })\">\n <mat-option value=\"\">Any</mat-option>\n @for (s of services.value() ?? []; track s.id) { <mat-option [value]=\"s.id\">{{ s.key }}</mat-option> }\n </mat-select>\n </mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\">\n <mat-label>Host</mat-label>\n <mat-select [ngModel]=\"resource() ?? ''\" (ngModelChange)=\"scope({ resource: $event || null, service: null })\">\n <mat-option value=\"\">Any</mat-option>\n @for (h of hosts.value() ?? []; track h.id) { <mat-option [value]=\"h.id\">{{ h.displayName }}</mat-option> }\n </mat-select>\n </mat-form-field>\n </div>\n <jc-metric-explorer [scope]=\"query()\" [initial]=\"metric() ?? null\" />`,\n})\nexport class MetricsPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n private readonly router = inject(Router);\n readonly service = input<string>();\n readonly resource = input<string>();\n readonly metric = input<string>();\n\n protected readonly services = apiResource({ stream: () => this.api.resources('service').pipe(map(p => p.items)) });\n protected readonly hosts = apiResource({ stream: () => this.api.resources('host').pipe(map(p => p.items)) });\n protected readonly query = computed(() => ({ serviceId: this.service(), resourceId: this.resource() }));\n\n scope(change: Record<string, string | null>) {\n void this.router.navigate([], { queryParams: change, queryParamsHandling: 'merge' });\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService, LinkPipe } from "./juice-js-observability.mjs";
2
- import { _ as ReasonPipe, a as problemText, l as ContextBar, m as AgoPipe, u as HealthBadge, x as apiResource } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { S as apiResource, d as HealthBadge, h as AgoPipe, o as problemText, u as ContextBar, v as ReasonPipe } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject } from "@angular/core";
5
5
  import { map } from "rxjs";
@@ -246,4 +246,4 @@ i0.ɵɵngDeclareClassMetadata({
246
246
  });
247
247
  export { OverviewPage };
248
248
 
249
- //# sourceMappingURL=juice-js-observability-overview.page-Cod7-cIy.mjs.map
249
+ //# sourceMappingURL=juice-js-observability-overview.page-DXZl_fUh.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"juice-js-observability-overview.page-Cod7-cIy.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/overview.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { map } from 'rxjs';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { HealthState } from '../core/models';\nimport { AgoPipe, ReasonPipe } from '../shared/format';\nimport { ContextBar, HealthBadge } from '../shared/ui';\nimport { problemText } from '../shared/telemetry';\n\nconst ORDER: HealthState[] = ['Critical', 'Unhealthy', 'Degraded', 'Offline', 'Unknown', 'Healthy'];\n\n/** How many rows each list shows: the overview orients, the alerts and services pages list everything. */\nconst SHOWN = 10;\n\n/**\n * Where an investigation starts (Console requirements §4, §21 step 1): what is firing and which services are not\n * healthy, each one click from its service page. Orientation, not a dashboard.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatProgressBarModule, ContextBar, HealthBadge, AgoPipe],\n template: `\n <jc-context-bar><h1>Overview</h1></jc-context-bar>\n @if (health.isLoading() || alerts.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (health.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n\n <div class=\"jc-tiles\">\n @for (s of order; track s) {\n <a class=\"jc-card jc-tile\" [routerLink]=\"['services'] | jcLink\" [queryParams]=\"ctx.keep({ state: s })\">\n <jc-health [state]=\"s\" /><strong>{{ counts()[s] ?? 0 }}</strong><span class=\"jc-muted\">services</span>\n </a>\n }\n </div>\n\n <section class=\"jc-card\">\n <div class=\"jc-row\">\n <h2>Firing alerts @if (firing().length) { <span class=\"jc-muted\">({{ firing().length }}@if (criticalCount()) { · {{ criticalCount() }} critical})</span> }</h2>\n @if (firing().length) { <a [routerLink]=\"['alerts'] | jcLink\" [queryParams]=\"ctx.keep({ state: 'firing' })\">All firing alerts</a> }\n </div>\n @for (a of firingShown(); track a.id) {\n <div class=\"jc-list-row\">\n <span class=\"jc-badge\" [class.jc-health-unhealthy]=\"a.severity === 'Critical'\" [class.jc-health-degraded]=\"a.severity !== 'Critical'\">{{ a.severity }}</span>\n <a [routerLink]=\"['alerts', a.id] | jcLink\" [queryParams]=\"ctx.keep()\">{{ a.rule }}</a>\n <span>{{ a.subjectKey }}</span>\n <span class=\"jc-muted\">fired {{ a.firedAt | ago }}@if (a.acknowledgedBy) { · acknowledged by {{ a.acknowledgedBy }} }</span>\n </div>\n } @empty { <p class=\"jc-muted\">Nothing firing.</p> }\n @if (firing().length > shown) {\n <p class=\"jc-more\"><span class=\"jc-muted\">Critical first, then the newest; {{ firing().length - shown }} more.</span>\n <a [routerLink]=\"['alerts'] | jcLink\" [queryParams]=\"ctx.keep({ state: 'firing' })\">See all {{ firing().length }}</a></p>\n }\n </section>\n\n <section class=\"jc-card\">\n <h2>Services needing attention @if (attention().length) { <span class=\"jc-muted\">({{ attention().length }})</span> }</h2>\n @for (h of attention().slice(0, shown); track h.subjectId + h.environment) {\n <div class=\"jc-list-row\">\n <jc-health [state]=\"h.state\" [stale]=\"h.stale\" />\n <a [routerLink]=\"['services', h.subjectId] | jcLink\" [queryParams]=\"ctx.keep({ env: h.environment })\">{{ h.subjectName }}</a>\n <span class=\"jc-muted\">{{ h.environment }}</span>\n <span>{{ h.reasons.slice(0, 3).map(reason).join(' · ') }}</span>\n <span class=\"jc-muted\">since {{ h.since | ago }}</span>\n </div>\n } @empty { <p class=\"jc-muted\">Every evaluated service is healthy.</p> }\n @if (attention().length > shown) {\n <p class=\"jc-more\"><span class=\"jc-muted\">The worst first; {{ attention().length - shown }} more. The counts above open each state's list:</span>\n @for (s of order; track s) { @if (s !== 'Healthy' && counts()[s]) {\n <a [routerLink]=\"['services'] | jcLink\" [queryParams]=\"ctx.keep({ state: s })\">{{ counts()[s] }} {{ s.toLowerCase() }}</a>\n } }</p>\n }\n </section>`,\n})\nexport class OverviewPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n protected readonly order = ORDER;\n protected readonly shown = SHOWN;\n private readonly reasonPipe = new ReasonPipe();\n protected readonly reason = (r: string) => this.reasonPipe.transform(r);\n\n protected readonly health = apiResource({\n params: () => this.ctx.environment(),\n stream: ({ params }) => this.api.health({ subjectType: 'service', environment: params }).pipe(map(p => p.items)),\n });\n protected readonly alerts = apiResource({\n params: () => this.ctx.environment(),\n stream: ({ params }) => this.api.allAlerts({ state: 'firing', environment: params }).pipe(map(p => p.items)),\n });\n protected readonly error = computed(() => problemText(this.health.error()));\n /** Critical first, then the newest. */\n protected readonly firing = computed(() => [...(this.alerts.value() ?? [])].sort((a, b) =>\n Number(b.severity === 'Critical') - Number(a.severity === 'Critical')\n || (b.firedAt ?? '').localeCompare(a.firedAt ?? '')));\n protected readonly firingShown = computed(() => this.firing().slice(0, SHOWN));\n protected readonly criticalCount = computed(() => this.firing().filter(a => a.severity === 'Critical').length);\n protected readonly counts = computed(() => {\n const counts: Partial<Record<HealthState, number>> = {};\n for (const h of this.health.value() ?? []) counts[h.state] = (counts[h.state] ?? 0) + 1;\n return counts;\n });\n protected readonly attention = computed(() => (this.health.value() ?? [])\n .filter(h => h.state !== 'Healthy')\n .sort((a, b) => ORDER.indexOf(a.state) - ORDER.indexOf(b.state)));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"juice-js-observability-overview.page-DXZl_fUh.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/overview.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { map } from 'rxjs';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { HealthState } from '../core/models';\nimport { AgoPipe, ReasonPipe } from '../shared/format';\nimport { ContextBar, HealthBadge } from '../shared/ui';\nimport { problemText } from '../shared/telemetry';\n\nconst ORDER: HealthState[] = ['Critical', 'Unhealthy', 'Degraded', 'Offline', 'Unknown', 'Healthy'];\n\n/** How many rows each list shows: the overview orients, the alerts and services pages list everything. */\nconst SHOWN = 10;\n\n/**\n * Where an investigation starts (Console requirements §4, §21 step 1): what is firing and which services are not\n * healthy, each one click from its service page. Orientation, not a dashboard.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatProgressBarModule, ContextBar, HealthBadge, AgoPipe],\n template: `\n <jc-context-bar><h1>Overview</h1></jc-context-bar>\n @if (health.isLoading() || alerts.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (health.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n\n <div class=\"jc-tiles\">\n @for (s of order; track s) {\n <a class=\"jc-card jc-tile\" [routerLink]=\"['services'] | jcLink\" [queryParams]=\"ctx.keep({ state: s })\">\n <jc-health [state]=\"s\" /><strong>{{ counts()[s] ?? 0 }}</strong><span class=\"jc-muted\">services</span>\n </a>\n }\n </div>\n\n <section class=\"jc-card\">\n <div class=\"jc-row\">\n <h2>Firing alerts @if (firing().length) { <span class=\"jc-muted\">({{ firing().length }}@if (criticalCount()) { · {{ criticalCount() }} critical})</span> }</h2>\n @if (firing().length) { <a [routerLink]=\"['alerts'] | jcLink\" [queryParams]=\"ctx.keep({ state: 'firing' })\">All firing alerts</a> }\n </div>\n @for (a of firingShown(); track a.id) {\n <div class=\"jc-list-row\">\n <span class=\"jc-badge\" [class.jc-health-unhealthy]=\"a.severity === 'Critical'\" [class.jc-health-degraded]=\"a.severity !== 'Critical'\">{{ a.severity }}</span>\n <a [routerLink]=\"['alerts', a.id] | jcLink\" [queryParams]=\"ctx.keep()\">{{ a.rule }}</a>\n <span>{{ a.subjectKey }}</span>\n <span class=\"jc-muted\">fired {{ a.firedAt | ago }}@if (a.acknowledgedBy) { · acknowledged by {{ a.acknowledgedBy }} }</span>\n </div>\n } @empty { <p class=\"jc-muted\">Nothing firing.</p> }\n @if (firing().length > shown) {\n <p class=\"jc-more\"><span class=\"jc-muted\">Critical first, then the newest; {{ firing().length - shown }} more.</span>\n <a [routerLink]=\"['alerts'] | jcLink\" [queryParams]=\"ctx.keep({ state: 'firing' })\">See all {{ firing().length }}</a></p>\n }\n </section>\n\n <section class=\"jc-card\">\n <h2>Services needing attention @if (attention().length) { <span class=\"jc-muted\">({{ attention().length }})</span> }</h2>\n @for (h of attention().slice(0, shown); track h.subjectId + h.environment) {\n <div class=\"jc-list-row\">\n <jc-health [state]=\"h.state\" [stale]=\"h.stale\" />\n <a [routerLink]=\"['services', h.subjectId] | jcLink\" [queryParams]=\"ctx.keep({ env: h.environment })\">{{ h.subjectName }}</a>\n <span class=\"jc-muted\">{{ h.environment }}</span>\n <span>{{ h.reasons.slice(0, 3).map(reason).join(' · ') }}</span>\n <span class=\"jc-muted\">since {{ h.since | ago }}</span>\n </div>\n } @empty { <p class=\"jc-muted\">Every evaluated service is healthy.</p> }\n @if (attention().length > shown) {\n <p class=\"jc-more\"><span class=\"jc-muted\">The worst first; {{ attention().length - shown }} more. The counts above open each state's list:</span>\n @for (s of order; track s) { @if (s !== 'Healthy' && counts()[s]) {\n <a [routerLink]=\"['services'] | jcLink\" [queryParams]=\"ctx.keep({ state: s })\">{{ counts()[s] }} {{ s.toLowerCase() }}</a>\n } }</p>\n }\n </section>`,\n})\nexport class OverviewPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n protected readonly order = ORDER;\n protected readonly shown = SHOWN;\n private readonly reasonPipe = new ReasonPipe();\n protected readonly reason = (r: string) => this.reasonPipe.transform(r);\n\n protected readonly health = apiResource({\n params: () => this.ctx.environment(),\n stream: ({ params }) => this.api.health({ subjectType: 'service', environment: params }).pipe(map(p => p.items)),\n });\n protected readonly alerts = apiResource({\n params: () => this.ctx.environment(),\n stream: ({ params }) => this.api.allAlerts({ state: 'firing', environment: params }).pipe(map(p => p.items)),\n });\n protected readonly error = computed(() => problemText(this.health.error()));\n /** Critical first, then the newest. */\n protected readonly firing = computed(() => [...(this.alerts.value() ?? [])].sort((a, b) =>\n Number(b.severity === 'Critical') - Number(a.severity === 'Critical')\n || (b.firedAt ?? '').localeCompare(a.firedAt ?? '')));\n protected readonly firingShown = computed(() => this.firing().slice(0, SHOWN));\n protected readonly criticalCount = computed(() => this.firing().filter(a => a.severity === 'Critical').length);\n protected readonly counts = computed(() => {\n const counts: Partial<Record<HealthState, number>> = {};\n for (const h of this.health.value() ?? []) counts[h.state] = (counts[h.state] ?? 0) + 1;\n return counts;\n });\n protected readonly attention = computed(() => (this.health.value() ?? [])\n .filter(h => h.state !== 'Healthy')\n .sort((a, b) => ORDER.indexOf(a.state) - ORDER.indexOf(b.state)));\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService, LinkPipe } from "./juice-js-observability.mjs";
2
- import { _ as ReasonPipe, a as problemText, c as ConfidenceBadge, d as KeyValueTable, i as TraceTable, l as ContextBar, m as AgoPipe, n as MetricExplorer, t as LogTable, u as HealthBadge, x as apiResource } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { S as apiResource, a as TraceTable, d as HealthBadge, f as KeyValueTable, h as AgoPipe, l as ConfidenceBadge, n as LogTable, o as problemText, r as MetricExplorer, u as ContextBar, v as ReasonPipe } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject, input } from "@angular/core";
5
5
  import { RouterLink } from "@angular/router";
@@ -271,4 +271,4 @@ i0.ɵɵngDeclareClassMetadata({
271
271
  });
272
272
  export { ResourcePage };
273
273
 
274
- //# sourceMappingURL=juice-js-observability-resource.page-C8RhUipF.mjs.map
274
+ //# sourceMappingURL=juice-js-observability-resource.page-CauDE6kK.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"juice-js-observability-resource.page-C8RhUipF.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/resource.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe, ReasonPipe } from '../shared/format';\nimport { ConfidenceBadge, ContextBar, HealthBadge, KeyValueTable } from '../shared/ui';\nimport { LogTable, MetricExplorer, TraceTable, problemText } from '../shared/telemetry';\n\n/**\n * A host, container, pod, database or destination (Console requirements §11): what runs on it or who uses it, its\n * health, and its telemetry. A database or destination has traces (the calls to it) but no logs or metrics of its own.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatProgressBarModule, ContextBar, HealthBadge, ConfidenceBadge, KeyValueTable, TraceTable, LogTable,\n MetricExplorer, AgoPipe],\n template: `\n <jc-context-bar>\n <a [routerLink]=\"['resources'] | jcLink\" [queryParams]=\"ctx.keep({ type: resource.value()?.type })\" class=\"jc-crumb\">Resources</a>\n <span class=\"jc-crumb-sep\">›</span>\n <h1>{{ resource.value()?.displayName ?? '…' }}</h1>\n <span class=\"jc-muted\">{{ resource.value()?.type }}</span>\n </jc-context-bar>\n @if (resource.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (resource.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n @if (resource.value(); as r) {\n <div class=\"jc-grid-2\">\n <section class=\"jc-card\">\n <h2>Identity</h2>\n <jc-kv [values]=\"{ key: r.key, 'first seen': r.firstSeen, 'last seen': r.lastSeen }\" />\n <jc-kv [values]=\"r.attributes\" empty=\"\" />\n @for (h of r.health; track h.subjectId) {\n <p><jc-health [state]=\"h.state\" [stale]=\"h.stale\" /> {{ h.reasons.map(reason).join(' · ') }}</p>\n }\n </section>\n <section class=\"jc-card\">\n @if (isInfrastructure()) {\n <h2>Instances running here</h2>\n @for (i of r.instances; track i.id) {\n <div class=\"jc-list-row\"><jc-health [state]=\"i.health\" /><span>{{ i.instanceKey }}</span>\n <span class=\"jc-muted\">{{ i.environment }}</span><span class=\"jc-muted\">{{ i.lastSeen | ago }}</span></div>\n } @empty { <p class=\"jc-muted\">No service instances seen on it.</p> }\n } @else {\n <h2>Used by</h2>\n @for (e of users(); track e.id) {\n <div class=\"jc-list-row\"><a [routerLink]=\"['services', e.source] | jcLink\" [queryParams]=\"ctx.keep()\">{{ name(e.source) }}</a>\n <span>{{ e.relation }}</span><jc-confidence [confidence]=\"e.confidence\" />\n <a [routerLink]=\"['topology'] | jcLink\" [queryParams]=\"ctx.keep({ edge: e.id })\">evidence</a></div>\n } @empty { <p class=\"jc-muted\">No users seen{{ ctx.environment() ? ' in ' + ctx.environment() : '' }}.</p> }\n }\n </section>\n </div>\n @if (isInfrastructure()) {\n <h2>Metrics</h2>\n <jc-metric-explorer [scope]=\"{ resourceId: id() }\" />\n <h2>Logs</h2>\n <jc-log-table [query]=\"{ resourceId: id() }\" />\n } @else {\n <h2>Traces that reach it</h2>\n <jc-trace-table [query]=\"{ resourceId: id() }\" />\n }\n }`,\n})\nexport class ResourcePage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n readonly id = input.required<string>();\n\n protected readonly resource = apiResource({ params: () => this.id(), stream: ({ params }) => this.api.resource(params) });\n protected readonly topology = apiResource({ params: () => this.ctx.environment(), stream: ({ params }) => this.api.topology(params || null) });\n protected readonly error = computed(() => problemText(this.resource.error()));\n protected readonly isInfrastructure = computed(() => ['host', 'container', 'k8s-pod'].includes(this.resource.value()?.type ?? ''));\n protected readonly users = computed(() => (this.topology.value()?.edges ?? []).filter(e => e.target === this.id()));\n private readonly reasonPipe = new ReasonPipe();\n protected readonly reason = (r: string) => this.reasonPipe.transform(r);\n\n name(id: string) { return this.topology.value()?.nodes.find(n => n.id === id)?.displayName ?? id; }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"juice-js-observability-resource.page-CauDE6kK.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/resource.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe, ReasonPipe } from '../shared/format';\nimport { ConfidenceBadge, ContextBar, HealthBadge, KeyValueTable } from '../shared/ui';\nimport { LogTable, MetricExplorer, TraceTable, problemText } from '../shared/telemetry';\n\n/**\n * A host, container, pod, database or destination (Console requirements §11): what runs on it or who uses it, its\n * health, and its telemetry. A database or destination has traces (the calls to it) but no logs or metrics of its own.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatProgressBarModule, ContextBar, HealthBadge, ConfidenceBadge, KeyValueTable, TraceTable, LogTable,\n MetricExplorer, AgoPipe],\n template: `\n <jc-context-bar>\n <a [routerLink]=\"['resources'] | jcLink\" [queryParams]=\"ctx.keep({ type: resource.value()?.type })\" class=\"jc-crumb\">Resources</a>\n <span class=\"jc-crumb-sep\">›</span>\n <h1>{{ resource.value()?.displayName ?? '…' }}</h1>\n <span class=\"jc-muted\">{{ resource.value()?.type }}</span>\n </jc-context-bar>\n @if (resource.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (resource.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n @if (resource.value(); as r) {\n <div class=\"jc-grid-2\">\n <section class=\"jc-card\">\n <h2>Identity</h2>\n <jc-kv [values]=\"{ key: r.key, 'first seen': r.firstSeen, 'last seen': r.lastSeen }\" />\n <jc-kv [values]=\"r.attributes\" empty=\"\" />\n @for (h of r.health; track h.subjectId) {\n <p><jc-health [state]=\"h.state\" [stale]=\"h.stale\" /> {{ h.reasons.map(reason).join(' · ') }}</p>\n }\n </section>\n <section class=\"jc-card\">\n @if (isInfrastructure()) {\n <h2>Instances running here</h2>\n @for (i of r.instances; track i.id) {\n <div class=\"jc-list-row\"><jc-health [state]=\"i.health\" /><span>{{ i.instanceKey }}</span>\n <span class=\"jc-muted\">{{ i.environment }}</span><span class=\"jc-muted\">{{ i.lastSeen | ago }}</span></div>\n } @empty { <p class=\"jc-muted\">No service instances seen on it.</p> }\n } @else {\n <h2>Used by</h2>\n @for (e of users(); track e.id) {\n <div class=\"jc-list-row\"><a [routerLink]=\"['services', e.source] | jcLink\" [queryParams]=\"ctx.keep()\">{{ name(e.source) }}</a>\n <span>{{ e.relation }}</span><jc-confidence [confidence]=\"e.confidence\" />\n <a [routerLink]=\"['topology'] | jcLink\" [queryParams]=\"ctx.keep({ edge: e.id })\">evidence</a></div>\n } @empty { <p class=\"jc-muted\">No users seen{{ ctx.environment() ? ' in ' + ctx.environment() : '' }}.</p> }\n }\n </section>\n </div>\n @if (isInfrastructure()) {\n <h2>Metrics</h2>\n <jc-metric-explorer [scope]=\"{ resourceId: id() }\" />\n <h2>Logs</h2>\n <jc-log-table [query]=\"{ resourceId: id() }\" />\n } @else {\n <h2>Traces that reach it</h2>\n <jc-trace-table [query]=\"{ resourceId: id() }\" />\n }\n }`,\n})\nexport class ResourcePage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n readonly id = input.required<string>();\n\n protected readonly resource = apiResource({ params: () => this.id(), stream: ({ params }) => this.api.resource(params) });\n protected readonly topology = apiResource({ params: () => this.ctx.environment(), stream: ({ params }) => this.api.topology(params || null) });\n protected readonly error = computed(() => problemText(this.resource.error()));\n protected readonly isInfrastructure = computed(() => ['host', 'container', 'k8s-pod'].includes(this.resource.value()?.type ?? ''));\n protected readonly users = computed(() => (this.topology.value()?.edges ?? []).filter(e => e.target === this.id()));\n private readonly reasonPipe = new ReasonPipe();\n protected readonly reason = (r: string) => this.reasonPipe.transform(r);\n\n name(id: string) { return this.topology.value()?.nodes.find(n => n.id === id)?.displayName ?? id; }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService, LinkPipe } from "./juice-js-observability.mjs";
2
- import { a as problemText, l as ContextBar, m as AgoPipe, s as screenPages, x as apiResource } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { S as apiResource, c as screenPages, h as AgoPipe, o as problemText, u as ContextBar } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject, input, signal } from "@angular/core";
5
5
  import { RouterLink } from "@angular/router";
@@ -206,4 +206,4 @@ i0.ɵɵngDeclareClassMetadata({
206
206
  });
207
207
  export { ResourcesPage };
208
208
 
209
- //# sourceMappingURL=juice-js-observability-resources.page-KadGxEAh.mjs.map
209
+ //# sourceMappingURL=juice-js-observability-resources.page-CukW8vVc.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"juice-js-observability-resources.page-KadGxEAh.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/resources.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject, input, signal } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { MatPaginatorModule } from '@angular/material/paginator';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { SearchablePage } from '@juice-js/layout';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe } from '../shared/format';\nimport { ContextBar } from '../shared/ui';\nimport { problemText } from '../shared/telemetry';\nimport { screenPages } from '../shared/paging';\n\nconst TYPES = ['host', 'container', 'k8s-pod', 'database', 'messaging-destination'];\n\n/**\n * Where services run and what they use (Console requirements §11): hosts, containers, pods, databases and\n * destinations, as discovery reconciled them. Never deleted automatically; renames come only from configured aliases.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatPaginatorModule, MatProgressBarModule, ContextBar, AgoPipe],\n template: `\n <jc-context-bar><h1>Resources</h1>\n @for (t of types; track t) {\n <a class=\"jc-chip\" [class.jc-selected]=\"t === (type() ?? 'host')\" [routerLink]=\"['resources'] | jcLink\" [queryParams]=\"ctx.keep({ type: t })\">{{ t }}</a>\n }\n </jc-context-bar>\n @if (resources.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (resources.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n @if (capped()) { <p class=\"jc-notice\">Showing the first 5,000 only. Narrow the list with the search box or a filter.</p> }\n <table class=\"jc-table\">\n <thead><tr><th>Name</th><th>Key</th><th>First seen</th><th>Last seen</th></tr></thead>\n <tbody>\n @for (r of pages.visible(); track r.id) {\n <tr><td><a [routerLink]=\"['resources', r.id] | jcLink\" [queryParams]=\"ctx.keep()\">{{ r.displayName }}</a></td>\n <td class=\"jc-mono jc-small\">{{ r.key }}</td><td>{{ r.firstSeen | ago }}</td><td>{{ r.lastSeen | ago }}</td></tr>\n } @empty { <tr><td colspan=\"4\" class=\"jc-muted\">None seen.</td></tr> }\n </tbody>\n </table>\n @if (pages.needed()) {\n <mat-paginator [length]=\"rows().length\" [pageSize]=\"pages.size()\" [pageIndex]=\"pages.index()\" [pageSizeOptions]=\"pages.sizes\"\n (page)=\"pages.change($event)\" aria-label=\"Pages\" />\n }`,\n})\nexport class ResourcesPage implements SearchablePage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n protected readonly types = TYPES;\n readonly type = input<string>();\n private readonly filter = signal('');\n\n protected readonly resources = apiResource({\n params: () => this.type() ?? 'host',\n stream: ({ params }) => this.api.resources(params),\n });\n protected readonly error = computed(() => problemText(this.resources.error()));\n protected readonly capped = computed(() => (this.resources.value()?.nextCursor ?? null) !== null);\n protected readonly rows = computed(() => (this.resources.value()?.items ?? [])\n .filter(r => !this.filter() || `${r.displayName} ${r.key}`.toLowerCase().includes(this.filter().toLowerCase())));\n\n protected readonly pages = screenPages(this.rows);\n\n onSearch(query: string) { this.filter.set(query); }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"juice-js-observability-resources.page-CukW8vVc.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/resources.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject, input, signal } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { MatPaginatorModule } from '@angular/material/paginator';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { SearchablePage } from '@juice-js/layout';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe } from '../shared/format';\nimport { ContextBar } from '../shared/ui';\nimport { problemText } from '../shared/telemetry';\nimport { screenPages } from '../shared/paging';\n\nconst TYPES = ['host', 'container', 'k8s-pod', 'database', 'messaging-destination'];\n\n/**\n * Where services run and what they use (Console requirements §11): hosts, containers, pods, databases and\n * destinations, as discovery reconciled them. Never deleted automatically; renames come only from configured aliases.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatPaginatorModule, MatProgressBarModule, ContextBar, AgoPipe],\n template: `\n <jc-context-bar><h1>Resources</h1>\n @for (t of types; track t) {\n <a class=\"jc-chip\" [class.jc-selected]=\"t === (type() ?? 'host')\" [routerLink]=\"['resources'] | jcLink\" [queryParams]=\"ctx.keep({ type: t })\">{{ t }}</a>\n }\n </jc-context-bar>\n @if (resources.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (resources.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n @if (capped()) { <p class=\"jc-notice\">Showing the first 5,000 only. Narrow the list with the search box or a filter.</p> }\n <table class=\"jc-table\">\n <thead><tr><th>Name</th><th>Key</th><th>First seen</th><th>Last seen</th></tr></thead>\n <tbody>\n @for (r of pages.visible(); track r.id) {\n <tr><td><a [routerLink]=\"['resources', r.id] | jcLink\" [queryParams]=\"ctx.keep()\">{{ r.displayName }}</a></td>\n <td class=\"jc-mono jc-small\">{{ r.key }}</td><td>{{ r.firstSeen | ago }}</td><td>{{ r.lastSeen | ago }}</td></tr>\n } @empty { <tr><td colspan=\"4\" class=\"jc-muted\">None seen.</td></tr> }\n </tbody>\n </table>\n @if (pages.needed()) {\n <mat-paginator [length]=\"rows().length\" [pageSize]=\"pages.size()\" [pageIndex]=\"pages.index()\" [pageSizeOptions]=\"pages.sizes\"\n (page)=\"pages.change($event)\" aria-label=\"Pages\" />\n }`,\n})\nexport class ResourcesPage implements SearchablePage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n protected readonly types = TYPES;\n readonly type = input<string>();\n private readonly filter = signal('');\n\n protected readonly resources = apiResource({\n params: () => this.type() ?? 'host',\n stream: ({ params }) => this.api.resources(params),\n });\n protected readonly error = computed(() => problemText(this.resources.error()));\n protected readonly capped = computed(() => (this.resources.value()?.nextCursor ?? null) !== null);\n protected readonly rows = computed(() => (this.resources.value()?.items ?? [])\n .filter(r => !this.filter() || `${r.displayName} ${r.key}`.toLowerCase().includes(this.filter().toLowerCase())));\n\n protected readonly pages = screenPages(this.rows);\n\n onSearch(query: string) { this.filter.set(query); }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService, LinkPipe } from "./juice-js-observability.mjs";
2
- import { a as problemText, l as ContextBar, m as AgoPipe, x as apiResource } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { S as apiResource, h as AgoPipe, o as problemText, u as ContextBar } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject } from "@angular/core";
5
5
  import { forkJoin, map } from "rxjs";
@@ -172,4 +172,4 @@ i0.ɵɵngDeclareClassMetadata({
172
172
  });
173
173
  export { RulesPage };
174
174
 
175
- //# sourceMappingURL=juice-js-observability-rules.page-DKWvNpu9.mjs.map
175
+ //# sourceMappingURL=juice-js-observability-rules.page-Crb07uWm.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"juice-js-observability-rules.page-DKWvNpu9.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/rules.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { forkJoin, map } from 'rxjs';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe } from '../shared/format';\nimport { ContextBar } from '../shared/ui';\nimport { problemText } from '../shared/telemetry';\n\n/**\n * Rules and their current state (Console requirements §14). Rules are typed templates in deployment configuration\n * (D5), so this page reads them; it never edits them and never takes a query.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatProgressBarModule, ContextBar, AgoPipe],\n template: `\n <jc-context-bar><h1>Rules</h1><span class=\"jc-muted\">From deployment configuration (rules.json); read-only.</span></jc-context-bar>\n @if (data.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (data.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n <table class=\"jc-table\">\n <thead><tr><th>Rule</th><th>Template</th><th>Severity</th><th>Threshold</th><th>Recovery</th><th>Wait</th><th>Open alerts</th><th>Last evaluation</th></tr></thead>\n <tbody>\n @for (r of rows(); track r.key) {\n <tr [class.jc-muted]=\"!r.enabled\">\n <td><strong>{{ r.name }}</strong><div class=\"jc-muted jc-small\">{{ r.key }}@if (!r.enabled) { · disabled }</div></td>\n <td>{{ r.template }}</td>\n <td>{{ r.severity }}</td>\n <td>{{ r.definition['threshold'] ?? '—' }}</td>\n <td>{{ r.definition['recoveryThreshold'] ?? '—' }}</td>\n <td>{{ r.definition['forDuration'] ?? '—' }}</td>\n <td>\n @for (a of r.open; track a.id) {\n <div><a [routerLink]=\"['alerts', a.id] | jcLink\" [queryParams]=\"ctx.keep()\">{{ a.state }}</a> {{ a.subjectKey }} = {{ a.lastValue ?? 'no data' }}</div>\n } @empty { <span class=\"jc-muted\">none</span> }\n </td>\n <td>{{ r.lastEvaluatedAt | ago }}</td>\n </tr>\n }\n </tbody>\n </table>`,\n})\nexport class RulesPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n protected readonly data = apiResource({\n stream: () => forkJoin({\n rules: this.api.rules().pipe(map(p => p.items)),\n firing: this.api.allAlerts({ state: 'firing' }).pipe(map(p => p.items)),\n pending: this.api.allAlerts({ state: 'pending' }).pipe(map(p => p.items)),\n }),\n });\n protected readonly error = computed(() => problemText(this.data.error()));\n protected readonly rows = computed(() => {\n const d = this.data.value();\n if (!d) return [];\n const open = [...d.firing, ...d.pending];\n return d.rules.map(r => {\n const mine = open.filter(a => a.rule === r.key);\n const last = mine.map(a => a.lastEvaluatedAt).sort().at(-1) ?? null;\n return { ...r, open: mine, lastEvaluatedAt: last };\n });\n });\n}\n"],"mappings":";;;;;;;;AA6CA,IAAa,YAAb,MAAa,UAAS;CACD,MAAM,OAAO,cAAc;CAC7B,MAAM,OAAO,UAAU;CACrB,OAAO,YAAY,EACpC,cAAc,SAAS;EACrB,OAAO,KAAK,IAAI,MAAK,CAAE,CAAC,KAAK,KAAI,MAAK,EAAE,KAAK,CAAC;EAC9C,QAAQ,KAAK,IAAI,UAAU,EAAE,OAAO,SAAQ,CAAE,CAAC,CAAC,KAAK,KAAI,MAAK,EAAE,KAAK,CAAC;EACtE,SAAS,KAAK,IAAI,UAAU,EAAE,OAAO,UAAS,CAAE,CAAC,CAAC,KAAK,KAAI,MAAK,EAAE,KAAK,CAAC;CACzE,CAAA,EACF,CAAA;CACkB,QAAQ,eAAe,YAAY,KAAK,KAAK,MAAK,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACtD,OAAO,eAAc;EACtC,MAAM,IAAI,KAAK,KAAK,MAAK;EACzB,IAAI,CAAC,GAAG,OAAO,CAAA;EACf,MAAM,OAAO,CAAC,GAAG,EAAE,QAAQ,GAAG,EAAE,OAAO;EACvC,OAAO,EAAE,MAAM,KAAI,MAAI;GACrB,MAAM,OAAO,KAAK,QAAO,MAAK,EAAE,SAAS,EAAE,GAAG;GAC9C,MAAM,OAAO,KAAK,KAAI,MAAK,EAAE,eAAe,CAAC,CAAC,KAAI,CAAE,CAAC,GAAG,EAAE,KAAK;GAC/D,OAAO;IAAE,GAAG;IAAG,MAAM;IAAM,iBAAiB;GAAI;EAClD,CAAC;CACH,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CApBS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAS,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAT,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAS,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UA1BV;;;;;;;;;;;;;;;;;;;;;;;;;EAwBC,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAzBS;IAAU,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAoB;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,cAAA;IAAA,UAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAtD;IAAQ,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAgD;IAAO,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AA2B9D,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAS,YAAA,CAAA;EA7BrB,MAAA;EAAU,MAAA,CAAA;GACT,iBAAiB,wBAAwB;GACzC,SAAS;IAAC;IAAU;IAAY;IAAsB;IAAY;GAAO;GACzE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;EAyBX,CAAA"}
1
+ {"version":3,"file":"juice-js-observability-rules.page-Crb07uWm.mjs","names":[],"sources":["../../../../projects/juice-js/observability/src/lib/pages/rules.page.ts"],"sourcesContent":["import { LinkPipe } from '../core/options';\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\nimport { apiResource } from '../shared/resource';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { RouterLink } from '@angular/router';\nimport { forkJoin, map } from 'rxjs';\nimport { ApiService } from '../core/api.service';\nimport { ContextService } from '../core/context.service';\nimport { AgoPipe } from '../shared/format';\nimport { ContextBar } from '../shared/ui';\nimport { problemText } from '../shared/telemetry';\n\n/**\n * Rules and their current state (Console requirements §14). Rules are typed templates in deployment configuration\n * (D5), so this page reads them; it never edits them and never takes a query.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LinkPipe, RouterLink, MatProgressBarModule, ContextBar, AgoPipe],\n template: `\n <jc-context-bar><h1>Rules</h1><span class=\"jc-muted\">From deployment configuration (rules.json); read-only.</span></jc-context-bar>\n @if (data.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (data.error()) { <p class=\"jc-error\">{{ error() }}</p> }\n <table class=\"jc-table\">\n <thead><tr><th>Rule</th><th>Template</th><th>Severity</th><th>Threshold</th><th>Recovery</th><th>Wait</th><th>Open alerts</th><th>Last evaluation</th></tr></thead>\n <tbody>\n @for (r of rows(); track r.key) {\n <tr [class.jc-muted]=\"!r.enabled\">\n <td><strong>{{ r.name }}</strong><div class=\"jc-muted jc-small\">{{ r.key }}@if (!r.enabled) { · disabled }</div></td>\n <td>{{ r.template }}</td>\n <td>{{ r.severity }}</td>\n <td>{{ r.definition['threshold'] ?? '—' }}</td>\n <td>{{ r.definition['recoveryThreshold'] ?? '—' }}</td>\n <td>{{ r.definition['forDuration'] ?? '—' }}</td>\n <td>\n @for (a of r.open; track a.id) {\n <div><a [routerLink]=\"['alerts', a.id] | jcLink\" [queryParams]=\"ctx.keep()\">{{ a.state }}</a> {{ a.subjectKey }} = {{ a.lastValue ?? 'no data' }}</div>\n } @empty { <span class=\"jc-muted\">none</span> }\n </td>\n <td>{{ r.lastEvaluatedAt | ago }}</td>\n </tr>\n }\n </tbody>\n </table>`,\n})\nexport class RulesPage {\n protected readonly ctx = inject(ContextService);\n private readonly api = inject(ApiService);\n protected readonly data = apiResource({\n stream: () => forkJoin({\n rules: this.api.rules().pipe(map(p => p.items)),\n firing: this.api.allAlerts({ state: 'firing' }).pipe(map(p => p.items)),\n pending: this.api.allAlerts({ state: 'pending' }).pipe(map(p => p.items)),\n }),\n });\n protected readonly error = computed(() => problemText(this.data.error()));\n protected readonly rows = computed(() => {\n const d = this.data.value();\n if (!d) return [];\n const open = [...d.firing, ...d.pending];\n return d.rules.map(r => {\n const mine = open.filter(a => a.rule === r.key);\n const last = mine.map(a => a.lastEvaluatedAt).sort().at(-1) ?? null;\n return { ...r, open: mine, lastEvaluatedAt: last };\n });\n });\n}\n"],"mappings":";;;;;;;;AA6CA,IAAa,YAAb,MAAa,UAAS;CACD,MAAM,OAAO,cAAc;CAC7B,MAAM,OAAO,UAAU;CACrB,OAAO,YAAY,EACpC,cAAc,SAAS;EACrB,OAAO,KAAK,IAAI,MAAK,CAAE,CAAC,KAAK,KAAI,MAAK,EAAE,KAAK,CAAC;EAC9C,QAAQ,KAAK,IAAI,UAAU,EAAE,OAAO,SAAQ,CAAE,CAAC,CAAC,KAAK,KAAI,MAAK,EAAE,KAAK,CAAC;EACtE,SAAS,KAAK,IAAI,UAAU,EAAE,OAAO,UAAS,CAAE,CAAC,CAAC,KAAK,KAAI,MAAK,EAAE,KAAK,CAAC;CACzE,CAAA,EACF,CAAA;CACkB,QAAQ,eAAe,YAAY,KAAK,KAAK,MAAK,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACtD,OAAO,eAAc;EACtC,MAAM,IAAI,KAAK,KAAK,MAAK;EACzB,IAAI,CAAC,GAAG,OAAO,CAAA;EACf,MAAM,OAAO,CAAC,GAAG,EAAE,QAAQ,GAAG,EAAE,OAAO;EACvC,OAAO,EAAE,MAAM,KAAI,MAAI;GACrB,MAAM,OAAO,KAAK,QAAO,MAAK,EAAE,SAAS,EAAE,GAAG;GAC9C,MAAM,OAAO,KAAK,KAAI,MAAK,EAAE,eAAe,CAAC,CAAC,KAAI,CAAE,CAAC,GAAG,EAAE,KAAK;GAC/D,OAAO;IAAE,GAAG;IAAG,MAAM;IAAM,iBAAiB;GAAI;EAClD,CAAC;CACH,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CApBS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAS,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAT,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAS,cAAA;EAAA,UAAA;EAAA,UAAA;EAAA,UA1BV;;;;;;;;;;;;;;;;;;;;;;;;;EAwBC,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAzBS;IAAU,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;GAAoB;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,cAAA;IAAA,UAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAtD;IAAQ,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAgD;IAAO,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AA2B9D,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAS,YAAA,CAAA;EA7BrB,MAAA;EAAU,MAAA,CAAA;GACT,iBAAiB,wBAAwB;GACzC,SAAS;IAAC;IAAU;IAAY;IAAsB;IAAY;GAAO;GACzE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;EAyBX,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { ApiService, ContextService, LinkPipe, ObservabilityLinks } from "./juice-js-observability.mjs";
2
- import { _ as ReasonPipe, a as problemText, c as ConfidenceBadge, g as PercentPipe, h as DurationPipe, i as TraceTable, l as ContextBar, m as AgoPipe, n as MetricExplorer, r as ServiceStatsCharts, t as LogTable, u as HealthBadge, x as apiResource } from "./juice-js-observability-telemetry-B5jMJYfn.mjs";
2
+ import { S as apiResource, _ as PercentPipe, a as TraceTable, d as HealthBadge, g as DurationPipe, h as AgoPipe, i as ServiceStatsCharts, l as ConfidenceBadge, n as LogTable, o as problemText, r as MetricExplorer, u as ContextBar, v as ReasonPipe } from "./juice-js-observability-telemetry-BftWSOaQ.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { ChangeDetectionStrategy, Component, computed, inject, input } from "@angular/core";
5
5
  import { Router, RouterLink } from "@angular/router";
@@ -723,4 +723,4 @@ i0.ɵɵngDeclareClassMetadata({
723
723
  });
724
724
  export { ServicePage };
725
725
 
726
- //# sourceMappingURL=juice-js-observability-service.page-_yK0kVYS.mjs.map
726
+ //# sourceMappingURL=juice-js-observability-service.page-Dt8bN2Ry.mjs.map