@juice-js/observability 0.0.0-stage → 1.0.0-alpha.1

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 (34) hide show
  1. package/README.md +31 -2
  2. package/fesm2022/juice-js-observability-alert.page-D2OL0zTT.mjs +405 -0
  3. package/fesm2022/juice-js-observability-alert.page-D2OL0zTT.mjs.map +1 -0
  4. package/fesm2022/juice-js-observability-alerts.page-BLJvD_op.mjs +208 -0
  5. package/fesm2022/juice-js-observability-alerts.page-BLJvD_op.mjs.map +1 -0
  6. package/fesm2022/juice-js-observability-logs.page-BWFLleyX.mjs +414 -0
  7. package/fesm2022/juice-js-observability-logs.page-BWFLleyX.mjs.map +1 -0
  8. package/fesm2022/juice-js-observability-metrics.page-D1caPbQq.mjs +268 -0
  9. package/fesm2022/juice-js-observability-metrics.page-D1caPbQq.mjs.map +1 -0
  10. package/fesm2022/juice-js-observability-overview.page-UBwHjlyq.mjs +213 -0
  11. package/fesm2022/juice-js-observability-overview.page-UBwHjlyq.mjs.map +1 -0
  12. package/fesm2022/juice-js-observability-resource.page-BZwLK_vU.mjs +275 -0
  13. package/fesm2022/juice-js-observability-resource.page-BZwLK_vU.mjs.map +1 -0
  14. package/fesm2022/juice-js-observability-resources.page-C0xWOb5I.mjs +210 -0
  15. package/fesm2022/juice-js-observability-resources.page-C0xWOb5I.mjs.map +1 -0
  16. package/fesm2022/juice-js-observability-rules.page-Db_U5rRu.mjs +176 -0
  17. package/fesm2022/juice-js-observability-rules.page-Db_U5rRu.mjs.map +1 -0
  18. package/fesm2022/juice-js-observability-service.page-B-SWJ9I5.mjs +727 -0
  19. package/fesm2022/juice-js-observability-service.page-B-SWJ9I5.mjs.map +1 -0
  20. package/fesm2022/juice-js-observability-services.page-BmWgFnC8.mjs +252 -0
  21. package/fesm2022/juice-js-observability-services.page-BmWgFnC8.mjs.map +1 -0
  22. package/fesm2022/juice-js-observability-telemetry-VA4_3nzr.mjs +1748 -0
  23. package/fesm2022/juice-js-observability-telemetry-VA4_3nzr.mjs.map +1 -0
  24. package/fesm2022/juice-js-observability-topology.page-DEUNp10U.mjs +458 -0
  25. package/fesm2022/juice-js-observability-topology.page-DEUNp10U.mjs.map +1 -0
  26. package/fesm2022/juice-js-observability-trace.page-gBhMG2eQ.mjs +530 -0
  27. package/fesm2022/juice-js-observability-trace.page-gBhMG2eQ.mjs.map +1 -0
  28. package/fesm2022/juice-js-observability-traces.page-BCQg4V4o.mjs +521 -0
  29. package/fesm2022/juice-js-observability-traces.page-BCQg4V4o.mjs.map +1 -0
  30. package/fesm2022/juice-js-observability.mjs +396 -0
  31. package/fesm2022/juice-js-observability.mjs.map +1 -0
  32. package/package.json +48 -4
  33. package/styles/_observability.scss +133 -0
  34. package/types/juice-js-observability.d.ts +387 -0
@@ -0,0 +1,275 @@
1
+ import { ApiService, ContextService, LinkPipe } from "./juice-js-observability.mjs";
2
+ import { a as problemText, c as ConfidenceBadge, d as KeyValueTable, f as AgoPipe, h as ReasonPipe, i as TraceTable, l as ContextBar, n as MetricExplorer, t as LogTable, u as HealthBadge } from "./juice-js-observability-telemetry-VA4_3nzr.mjs";
3
+ import * as i0 from "@angular/core";
4
+ import { ChangeDetectionStrategy, Component, computed, inject, input } from "@angular/core";
5
+ import { rxResource } from "@angular/core/rxjs-interop";
6
+ import { RouterLink } from "@angular/router";
7
+ import * as i1 from "@angular/material/progress-bar";
8
+ import { MatProgressBarModule } from "@angular/material/progress-bar";
9
+ var ResourcePage = class ResourcePage {
10
+ ctx = inject(ContextService);
11
+ api = inject(ApiService);
12
+ id = input.required(...ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []);
13
+ resource = rxResource({
14
+ params: () => this.id(),
15
+ stream: ({ params }) => this.api.resource(params)
16
+ });
17
+ topology = rxResource({
18
+ params: () => this.ctx.environment(),
19
+ stream: ({ params }) => this.api.topology(params || null)
20
+ });
21
+ error = computed(() => problemText(this.resource.error()), ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
22
+ isInfrastructure = computed(() => [
23
+ "host",
24
+ "container",
25
+ "k8s-pod"
26
+ ].includes(this.resource.value()?.type ?? ""), ...ngDevMode ? [{ debugName: "isInfrastructure" }] : /* istanbul ignore next */ []);
27
+ users = computed(() => (this.topology.value()?.edges ?? []).filter((e) => e.target === this.id()), ...ngDevMode ? [{ debugName: "users" }] : /* istanbul ignore next */ []);
28
+ reasonPipe = new ReasonPipe();
29
+ reason = (r) => this.reasonPipe.transform(r);
30
+ name(id) {
31
+ return this.topology.value()?.nodes.find((n) => n.id === id)?.displayName ?? id;
32
+ }
33
+ static ɵfac = i0.ɵɵngDeclareFactory({
34
+ minVersion: "12.0.0",
35
+ version: "22.2.4",
36
+ ngImport: i0,
37
+ type: ResourcePage,
38
+ deps: [],
39
+ target: i0.ɵɵFactoryTarget.Component
40
+ });
41
+ static ɵcmp = i0.ɵɵngDeclareComponent({
42
+ minVersion: "17.0.0",
43
+ version: "22.2.4",
44
+ type: ResourcePage,
45
+ isStandalone: true,
46
+ selector: "ng-component",
47
+ inputs: { id: {
48
+ classPropertyName: "id",
49
+ publicName: "id",
50
+ isSignal: true,
51
+ isRequired: true,
52
+ transformFunction: null
53
+ } },
54
+ ngImport: i0,
55
+ template: `
56
+ <jc-context-bar>
57
+ <a [routerLink]="['resources'] | jcLink" [queryParams]="ctx.keep({ type: resource.value()?.type })" class="jc-crumb">Resources</a>
58
+ <span class="jc-crumb-sep">›</span>
59
+ <h1>{{ resource.value()?.displayName ?? '…' }}</h1>
60
+ <span class="jc-muted">{{ resource.value()?.type }}</span>
61
+ </jc-context-bar>
62
+ @if (resource.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
63
+ @if (resource.error()) { <p class="jc-error">{{ error() }}</p> }
64
+ @if (resource.value(); as r) {
65
+ <div class="jc-grid-2">
66
+ <section class="jc-card">
67
+ <h2>Identity</h2>
68
+ <jc-kv [values]="{ key: r.key, 'first seen': r.firstSeen, 'last seen': r.lastSeen }" />
69
+ <jc-kv [values]="r.attributes" empty="" />
70
+ @for (h of r.health; track h.subjectId) {
71
+ <p><jc-health [state]="h.state" [stale]="h.stale" /> {{ h.reasons.map(reason).join(' · ') }}</p>
72
+ }
73
+ </section>
74
+ <section class="jc-card">
75
+ @if (isInfrastructure()) {
76
+ <h2>Instances running here</h2>
77
+ @for (i of r.instances; track i.id) {
78
+ <div class="jc-list-row"><jc-health [state]="i.health" /><span>{{ i.instanceKey }}</span>
79
+ <span class="jc-muted">{{ i.environment }}</span><span class="jc-muted">{{ i.lastSeen | ago }}</span></div>
80
+ } @empty { <p class="jc-muted">No service instances seen on it.</p> }
81
+ } @else {
82
+ <h2>Used by</h2>
83
+ @for (e of users(); track e.id) {
84
+ <div class="jc-list-row"><a [routerLink]="['services', e.source] | jcLink" [queryParams]="ctx.keep()">{{ name(e.source) }}</a>
85
+ <span>{{ e.relation }}</span><jc-confidence [confidence]="e.confidence" />
86
+ <a [routerLink]="['topology'] | jcLink" [queryParams]="ctx.keep({ edge: e.id })">evidence</a></div>
87
+ } @empty { <p class="jc-muted">No users seen{{ ctx.environment() ? ' in ' + ctx.environment() : '' }}.</p> }
88
+ }
89
+ </section>
90
+ </div>
91
+ @if (isInfrastructure()) {
92
+ <h2>Metrics</h2>
93
+ <jc-metric-explorer [scope]="{ resourceId: id() }" />
94
+ <h2>Logs</h2>
95
+ <jc-log-table [query]="{ resourceId: id() }" />
96
+ } @else {
97
+ <h2>Traces that reach it</h2>
98
+ <jc-trace-table [query]="{ resourceId: id() }" />
99
+ }
100
+ }`,
101
+ isInline: true,
102
+ dependencies: [
103
+ {
104
+ kind: "directive",
105
+ type: RouterLink,
106
+ selector: "[routerLink]",
107
+ inputs: [
108
+ "target",
109
+ "queryParams",
110
+ "fragment",
111
+ "queryParamsHandling",
112
+ "state",
113
+ "info",
114
+ "relativeTo",
115
+ "preserveFragment",
116
+ "skipLocationChange",
117
+ "replaceUrl",
118
+ "browserUrl",
119
+ "routerLink"
120
+ ]
121
+ },
122
+ {
123
+ kind: "ngmodule",
124
+ type: MatProgressBarModule
125
+ },
126
+ {
127
+ kind: "component",
128
+ type: i1.MatProgressBar,
129
+ selector: "mat-progress-bar",
130
+ inputs: [
131
+ "color",
132
+ "value",
133
+ "bufferValue",
134
+ "mode"
135
+ ],
136
+ outputs: ["animationEnd"],
137
+ exportAs: ["matProgressBar"]
138
+ },
139
+ {
140
+ kind: "component",
141
+ type: ContextBar,
142
+ selector: "jc-context-bar"
143
+ },
144
+ {
145
+ kind: "component",
146
+ type: HealthBadge,
147
+ selector: "jc-health",
148
+ inputs: ["state", "stale"]
149
+ },
150
+ {
151
+ kind: "component",
152
+ type: ConfidenceBadge,
153
+ selector: "jc-confidence",
154
+ inputs: ["confidence"]
155
+ },
156
+ {
157
+ kind: "component",
158
+ type: KeyValueTable,
159
+ selector: "jc-kv",
160
+ inputs: ["values", "empty"]
161
+ },
162
+ {
163
+ kind: "component",
164
+ type: TraceTable,
165
+ selector: "jc-trace-table",
166
+ inputs: ["query", "limit"]
167
+ },
168
+ {
169
+ kind: "component",
170
+ type: LogTable,
171
+ selector: "jc-log-table",
172
+ inputs: ["query", "compact"]
173
+ },
174
+ {
175
+ kind: "component",
176
+ type: MetricExplorer,
177
+ selector: "jc-metric-explorer",
178
+ inputs: ["scope", "initial"]
179
+ },
180
+ {
181
+ kind: "pipe",
182
+ type: LinkPipe,
183
+ name: "jcLink"
184
+ },
185
+ {
186
+ kind: "pipe",
187
+ type: AgoPipe,
188
+ name: "ago"
189
+ }
190
+ ],
191
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
192
+ });
193
+ };
194
+ i0.ɵɵngDeclareClassMetadata({
195
+ minVersion: "12.0.0",
196
+ version: "22.2.4",
197
+ ngImport: i0,
198
+ type: ResourcePage,
199
+ decorators: [{
200
+ type: Component,
201
+ args: [{
202
+ changeDetection: ChangeDetectionStrategy.OnPush,
203
+ imports: [
204
+ LinkPipe,
205
+ RouterLink,
206
+ MatProgressBarModule,
207
+ ContextBar,
208
+ HealthBadge,
209
+ ConfidenceBadge,
210
+ KeyValueTable,
211
+ TraceTable,
212
+ LogTable,
213
+ MetricExplorer,
214
+ AgoPipe
215
+ ],
216
+ template: `
217
+ <jc-context-bar>
218
+ <a [routerLink]="['resources'] | jcLink" [queryParams]="ctx.keep({ type: resource.value()?.type })" class="jc-crumb">Resources</a>
219
+ <span class="jc-crumb-sep">›</span>
220
+ <h1>{{ resource.value()?.displayName ?? '…' }}</h1>
221
+ <span class="jc-muted">{{ resource.value()?.type }}</span>
222
+ </jc-context-bar>
223
+ @if (resource.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
224
+ @if (resource.error()) { <p class="jc-error">{{ error() }}</p> }
225
+ @if (resource.value(); as r) {
226
+ <div class="jc-grid-2">
227
+ <section class="jc-card">
228
+ <h2>Identity</h2>
229
+ <jc-kv [values]="{ key: r.key, 'first seen': r.firstSeen, 'last seen': r.lastSeen }" />
230
+ <jc-kv [values]="r.attributes" empty="" />
231
+ @for (h of r.health; track h.subjectId) {
232
+ <p><jc-health [state]="h.state" [stale]="h.stale" /> {{ h.reasons.map(reason).join(' · ') }}</p>
233
+ }
234
+ </section>
235
+ <section class="jc-card">
236
+ @if (isInfrastructure()) {
237
+ <h2>Instances running here</h2>
238
+ @for (i of r.instances; track i.id) {
239
+ <div class="jc-list-row"><jc-health [state]="i.health" /><span>{{ i.instanceKey }}</span>
240
+ <span class="jc-muted">{{ i.environment }}</span><span class="jc-muted">{{ i.lastSeen | ago }}</span></div>
241
+ } @empty { <p class="jc-muted">No service instances seen on it.</p> }
242
+ } @else {
243
+ <h2>Used by</h2>
244
+ @for (e of users(); track e.id) {
245
+ <div class="jc-list-row"><a [routerLink]="['services', e.source] | jcLink" [queryParams]="ctx.keep()">{{ name(e.source) }}</a>
246
+ <span>{{ e.relation }}</span><jc-confidence [confidence]="e.confidence" />
247
+ <a [routerLink]="['topology'] | jcLink" [queryParams]="ctx.keep({ edge: e.id })">evidence</a></div>
248
+ } @empty { <p class="jc-muted">No users seen{{ ctx.environment() ? ' in ' + ctx.environment() : '' }}.</p> }
249
+ }
250
+ </section>
251
+ </div>
252
+ @if (isInfrastructure()) {
253
+ <h2>Metrics</h2>
254
+ <jc-metric-explorer [scope]="{ resourceId: id() }" />
255
+ <h2>Logs</h2>
256
+ <jc-log-table [query]="{ resourceId: id() }" />
257
+ } @else {
258
+ <h2>Traces that reach it</h2>
259
+ <jc-trace-table [query]="{ resourceId: id() }" />
260
+ }
261
+ }`
262
+ }]
263
+ }],
264
+ propDecorators: { id: [{
265
+ type: i0.Input,
266
+ args: [{
267
+ isSignal: true,
268
+ alias: "id",
269
+ required: true
270
+ }]
271
+ }] }
272
+ });
273
+ export { ResourcePage };
274
+
275
+ //# sourceMappingURL=juice-js-observability-resource.page-BZwLK_vU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juice-js-observability-resource.page-BZwLK_vU.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 { rxResource } from '@angular/core/rxjs-interop';\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 = rxResource({ params: () => this.id(), stream: ({ params }) => this.api.resource(params) });\n protected readonly topology = rxResource({ 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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"}
@@ -0,0 +1,210 @@
1
+ import { ApiService, ContextService, LinkPipe } from "./juice-js-observability.mjs";
2
+ import { a as problemText, f as AgoPipe, l as ContextBar, s as screenPages } from "./juice-js-observability-telemetry-VA4_3nzr.mjs";
3
+ import * as i0 from "@angular/core";
4
+ import { ChangeDetectionStrategy, Component, computed, inject, input, signal } from "@angular/core";
5
+ import { rxResource } from "@angular/core/rxjs-interop";
6
+ import { RouterLink } from "@angular/router";
7
+ import * as i2 from "@angular/material/progress-bar";
8
+ import { MatProgressBarModule } from "@angular/material/progress-bar";
9
+ import * as i1 from "@angular/material/paginator";
10
+ import { MatPaginatorModule } from "@angular/material/paginator";
11
+ const TYPES = [
12
+ "host",
13
+ "container",
14
+ "k8s-pod",
15
+ "database",
16
+ "messaging-destination"
17
+ ];
18
+ var ResourcesPage = class ResourcesPage {
19
+ ctx = inject(ContextService);
20
+ api = inject(ApiService);
21
+ types = TYPES;
22
+ type = input(...ngDevMode ? [void 0, { debugName: "type" }] : /* istanbul ignore next */ []);
23
+ filter = signal("", ...ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []);
24
+ resources = rxResource({
25
+ params: () => this.type() ?? "host",
26
+ stream: ({ params }) => this.api.resources(params)
27
+ });
28
+ error = computed(() => problemText(this.resources.error()), ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
29
+ capped = computed(() => (this.resources.value()?.nextCursor ?? null) !== null, ...ngDevMode ? [{ debugName: "capped" }] : /* istanbul ignore next */ []);
30
+ rows = computed(() => (this.resources.value()?.items ?? []).filter((r) => !this.filter() || `${r.displayName} ${r.key}`.toLowerCase().includes(this.filter().toLowerCase())), ...ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []);
31
+ pages = screenPages(this.rows);
32
+ onSearch(query) {
33
+ this.filter.set(query);
34
+ }
35
+ static ɵfac = i0.ɵɵngDeclareFactory({
36
+ minVersion: "12.0.0",
37
+ version: "22.2.4",
38
+ ngImport: i0,
39
+ type: ResourcesPage,
40
+ deps: [],
41
+ target: i0.ɵɵFactoryTarget.Component
42
+ });
43
+ static ɵcmp = i0.ɵɵngDeclareComponent({
44
+ minVersion: "17.0.0",
45
+ version: "22.2.4",
46
+ type: ResourcesPage,
47
+ isStandalone: true,
48
+ selector: "ng-component",
49
+ inputs: { type: {
50
+ classPropertyName: "type",
51
+ publicName: "type",
52
+ isSignal: true,
53
+ isRequired: false,
54
+ transformFunction: null
55
+ } },
56
+ ngImport: i0,
57
+ template: `
58
+ <jc-context-bar><h1>Resources</h1>
59
+ @for (t of types; track t) {
60
+ <a class="jc-chip" [class.jc-selected]="t === (type() ?? 'host')" [routerLink]="['resources'] | jcLink" [queryParams]="ctx.keep({ type: t })">{{ t }}</a>
61
+ }
62
+ </jc-context-bar>
63
+ @if (resources.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
64
+ @if (resources.error()) { <p class="jc-error">{{ error() }}</p> }
65
+ @if (capped()) { <p class="jc-notice">Showing the first 5,000 only. Narrow the list with the search box or a filter.</p> }
66
+ <table class="jc-table">
67
+ <thead><tr><th>Name</th><th>Key</th><th>First seen</th><th>Last seen</th></tr></thead>
68
+ <tbody>
69
+ @for (r of pages.visible(); track r.id) {
70
+ <tr><td><a [routerLink]="['resources', r.id] | jcLink" [queryParams]="ctx.keep()">{{ r.displayName }}</a></td>
71
+ <td class="jc-mono jc-small">{{ r.key }}</td><td>{{ r.firstSeen | ago }}</td><td>{{ r.lastSeen | ago }}</td></tr>
72
+ } @empty { <tr><td colspan="4" class="jc-muted">None seen.</td></tr> }
73
+ </tbody>
74
+ </table>
75
+ @if (pages.needed()) {
76
+ <mat-paginator [length]="rows().length" [pageSize]="pages.size()" [pageIndex]="pages.index()" [pageSizeOptions]="pages.sizes"
77
+ (page)="pages.change($event)" aria-label="Pages" />
78
+ }`,
79
+ isInline: true,
80
+ dependencies: [
81
+ {
82
+ kind: "directive",
83
+ type: RouterLink,
84
+ selector: "[routerLink]",
85
+ inputs: [
86
+ "target",
87
+ "queryParams",
88
+ "fragment",
89
+ "queryParamsHandling",
90
+ "state",
91
+ "info",
92
+ "relativeTo",
93
+ "preserveFragment",
94
+ "skipLocationChange",
95
+ "replaceUrl",
96
+ "browserUrl",
97
+ "routerLink"
98
+ ]
99
+ },
100
+ {
101
+ kind: "ngmodule",
102
+ type: MatPaginatorModule
103
+ },
104
+ {
105
+ kind: "component",
106
+ type: i1.MatPaginator,
107
+ selector: "mat-paginator",
108
+ inputs: [
109
+ "color",
110
+ "pageIndex",
111
+ "length",
112
+ "pageSize",
113
+ "pageSizeOptions",
114
+ "hidePageSize",
115
+ "showFirstLastButtons",
116
+ "selectConfig",
117
+ "disabled"
118
+ ],
119
+ outputs: ["page"],
120
+ exportAs: ["matPaginator"]
121
+ },
122
+ {
123
+ kind: "ngmodule",
124
+ type: MatProgressBarModule
125
+ },
126
+ {
127
+ kind: "component",
128
+ type: i2.MatProgressBar,
129
+ selector: "mat-progress-bar",
130
+ inputs: [
131
+ "color",
132
+ "value",
133
+ "bufferValue",
134
+ "mode"
135
+ ],
136
+ outputs: ["animationEnd"],
137
+ exportAs: ["matProgressBar"]
138
+ },
139
+ {
140
+ kind: "component",
141
+ type: ContextBar,
142
+ selector: "jc-context-bar"
143
+ },
144
+ {
145
+ kind: "pipe",
146
+ type: LinkPipe,
147
+ name: "jcLink"
148
+ },
149
+ {
150
+ kind: "pipe",
151
+ type: AgoPipe,
152
+ name: "ago"
153
+ }
154
+ ],
155
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
156
+ });
157
+ };
158
+ i0.ɵɵngDeclareClassMetadata({
159
+ minVersion: "12.0.0",
160
+ version: "22.2.4",
161
+ ngImport: i0,
162
+ type: ResourcesPage,
163
+ decorators: [{
164
+ type: Component,
165
+ args: [{
166
+ changeDetection: ChangeDetectionStrategy.OnPush,
167
+ imports: [
168
+ LinkPipe,
169
+ RouterLink,
170
+ MatPaginatorModule,
171
+ MatProgressBarModule,
172
+ ContextBar,
173
+ AgoPipe
174
+ ],
175
+ template: `
176
+ <jc-context-bar><h1>Resources</h1>
177
+ @for (t of types; track t) {
178
+ <a class="jc-chip" [class.jc-selected]="t === (type() ?? 'host')" [routerLink]="['resources'] | jcLink" [queryParams]="ctx.keep({ type: t })">{{ t }}</a>
179
+ }
180
+ </jc-context-bar>
181
+ @if (resources.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
182
+ @if (resources.error()) { <p class="jc-error">{{ error() }}</p> }
183
+ @if (capped()) { <p class="jc-notice">Showing the first 5,000 only. Narrow the list with the search box or a filter.</p> }
184
+ <table class="jc-table">
185
+ <thead><tr><th>Name</th><th>Key</th><th>First seen</th><th>Last seen</th></tr></thead>
186
+ <tbody>
187
+ @for (r of pages.visible(); track r.id) {
188
+ <tr><td><a [routerLink]="['resources', r.id] | jcLink" [queryParams]="ctx.keep()">{{ r.displayName }}</a></td>
189
+ <td class="jc-mono jc-small">{{ r.key }}</td><td>{{ r.firstSeen | ago }}</td><td>{{ r.lastSeen | ago }}</td></tr>
190
+ } @empty { <tr><td colspan="4" class="jc-muted">None seen.</td></tr> }
191
+ </tbody>
192
+ </table>
193
+ @if (pages.needed()) {
194
+ <mat-paginator [length]="rows().length" [pageSize]="pages.size()" [pageIndex]="pages.index()" [pageSizeOptions]="pages.sizes"
195
+ (page)="pages.change($event)" aria-label="Pages" />
196
+ }`
197
+ }]
198
+ }],
199
+ propDecorators: { type: [{
200
+ type: i0.Input,
201
+ args: [{
202
+ isSignal: true,
203
+ alias: "type",
204
+ required: false
205
+ }]
206
+ }] }
207
+ });
208
+ export { ResourcesPage };
209
+
210
+ //# sourceMappingURL=juice-js-observability-resources.page-C0xWOb5I.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juice-js-observability-resources.page-C0xWOb5I.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 { rxResource } from '@angular/core/rxjs-interop';\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 = rxResource({\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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"}