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

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 +60 -2
  2. package/fesm2022/juice-js-observability-alert.page-BHKAUvR-.mjs +404 -0
  3. package/fesm2022/juice-js-observability-alert.page-BHKAUvR-.mjs.map +1 -0
  4. package/fesm2022/juice-js-observability-alerts.page-C2tXzLQl.mjs +208 -0
  5. package/fesm2022/juice-js-observability-alerts.page-C2tXzLQl.mjs.map +1 -0
  6. package/fesm2022/juice-js-observability-logs.page--j6W1Ej-.mjs +413 -0
  7. package/fesm2022/juice-js-observability-logs.page--j6W1Ej-.mjs.map +1 -0
  8. package/fesm2022/juice-js-observability-metrics.page-DR6qZtfl.mjs +267 -0
  9. package/fesm2022/juice-js-observability-metrics.page-DR6qZtfl.mjs.map +1 -0
  10. package/fesm2022/juice-js-observability-overview.page-DU0GxSXQ.mjs +243 -0
  11. package/fesm2022/juice-js-observability-overview.page-DU0GxSXQ.mjs.map +1 -0
  12. package/fesm2022/juice-js-observability-resource.page-D6qpvo_f.mjs +274 -0
  13. package/fesm2022/juice-js-observability-resource.page-D6qpvo_f.mjs.map +1 -0
  14. package/fesm2022/juice-js-observability-resources.page-CR7-DFsh.mjs +209 -0
  15. package/fesm2022/juice-js-observability-resources.page-CR7-DFsh.mjs.map +1 -0
  16. package/fesm2022/juice-js-observability-rules.page-fq-wO5I_.mjs +175 -0
  17. package/fesm2022/juice-js-observability-rules.page-fq-wO5I_.mjs.map +1 -0
  18. package/fesm2022/juice-js-observability-service.page-Qc6FYChB.mjs +726 -0
  19. package/fesm2022/juice-js-observability-service.page-Qc6FYChB.mjs.map +1 -0
  20. package/fesm2022/juice-js-observability-services.page-CX6S7sUu.mjs +251 -0
  21. package/fesm2022/juice-js-observability-services.page-CX6S7sUu.mjs.map +1 -0
  22. package/fesm2022/juice-js-observability-telemetry-D9EYxkdr.mjs +1783 -0
  23. package/fesm2022/juice-js-observability-telemetry-D9EYxkdr.mjs.map +1 -0
  24. package/fesm2022/juice-js-observability-topology.page-CLz7J5pq.mjs +483 -0
  25. package/fesm2022/juice-js-observability-topology.page-CLz7J5pq.mjs.map +1 -0
  26. package/fesm2022/juice-js-observability-trace.page-DccvH1SV.mjs +518 -0
  27. package/fesm2022/juice-js-observability-trace.page-DccvH1SV.mjs.map +1 -0
  28. package/fesm2022/juice-js-observability-traces.page-BZxnac4Y.mjs +520 -0
  29. package/fesm2022/juice-js-observability-traces.page-BZxnac4Y.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 +216 -0
  34. package/types/juice-js-observability.d.ts +387 -0
@@ -0,0 +1,274 @@
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-D9EYxkdr.mjs";
3
+ import * as i0 from "@angular/core";
4
+ import { ChangeDetectionStrategy, Component, computed, inject, input } from "@angular/core";
5
+ import { RouterLink } from "@angular/router";
6
+ import * as i1 from "@angular/material/progress-bar";
7
+ import { MatProgressBarModule } from "@angular/material/progress-bar";
8
+ var ResourcePage = class ResourcePage {
9
+ ctx = inject(ContextService);
10
+ api = inject(ApiService);
11
+ id = input.required(...ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []);
12
+ resource = apiResource({
13
+ params: () => this.id(),
14
+ stream: ({ params }) => this.api.resource(params)
15
+ });
16
+ topology = apiResource({
17
+ params: () => this.ctx.environment(),
18
+ stream: ({ params }) => this.api.topology(params || null)
19
+ });
20
+ error = computed(() => problemText(this.resource.error()), ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
21
+ isInfrastructure = computed(() => [
22
+ "host",
23
+ "container",
24
+ "k8s-pod"
25
+ ].includes(this.resource.value()?.type ?? ""), ...ngDevMode ? [{ debugName: "isInfrastructure" }] : /* istanbul ignore next */ []);
26
+ users = computed(() => (this.topology.value()?.edges ?? []).filter((e) => e.target === this.id()), ...ngDevMode ? [{ debugName: "users" }] : /* istanbul ignore next */ []);
27
+ reasonPipe = new ReasonPipe();
28
+ reason = (r) => this.reasonPipe.transform(r);
29
+ name(id) {
30
+ return this.topology.value()?.nodes.find((n) => n.id === id)?.displayName ?? id;
31
+ }
32
+ static ɵfac = i0.ɵɵngDeclareFactory({
33
+ minVersion: "12.0.0",
34
+ version: "22.2.4",
35
+ ngImport: i0,
36
+ type: ResourcePage,
37
+ deps: [],
38
+ target: i0.ɵɵFactoryTarget.Component
39
+ });
40
+ static ɵcmp = i0.ɵɵngDeclareComponent({
41
+ minVersion: "17.0.0",
42
+ version: "22.2.4",
43
+ type: ResourcePage,
44
+ isStandalone: true,
45
+ selector: "ng-component",
46
+ inputs: { id: {
47
+ classPropertyName: "id",
48
+ publicName: "id",
49
+ isSignal: true,
50
+ isRequired: true,
51
+ transformFunction: null
52
+ } },
53
+ ngImport: i0,
54
+ template: `
55
+ <jc-context-bar>
56
+ <a [routerLink]="['resources'] | jcLink" [queryParams]="ctx.keep({ type: resource.value()?.type })" class="jc-crumb">Resources</a>
57
+ <span class="jc-crumb-sep">›</span>
58
+ <h1>{{ resource.value()?.displayName ?? '…' }}</h1>
59
+ <span class="jc-muted">{{ resource.value()?.type }}</span>
60
+ </jc-context-bar>
61
+ @if (resource.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
62
+ @if (resource.error()) { <p class="jc-error">{{ error() }}</p> }
63
+ @if (resource.value(); as r) {
64
+ <div class="jc-grid-2">
65
+ <section class="jc-card">
66
+ <h2>Identity</h2>
67
+ <jc-kv [values]="{ key: r.key, 'first seen': r.firstSeen, 'last seen': r.lastSeen }" />
68
+ <jc-kv [values]="r.attributes" empty="" />
69
+ @for (h of r.health; track h.subjectId) {
70
+ <p><jc-health [state]="h.state" [stale]="h.stale" /> {{ h.reasons.map(reason).join(' · ') }}</p>
71
+ }
72
+ </section>
73
+ <section class="jc-card">
74
+ @if (isInfrastructure()) {
75
+ <h2>Instances running here</h2>
76
+ @for (i of r.instances; track i.id) {
77
+ <div class="jc-list-row"><jc-health [state]="i.health" /><span>{{ i.instanceKey }}</span>
78
+ <span class="jc-muted">{{ i.environment }}</span><span class="jc-muted">{{ i.lastSeen | ago }}</span></div>
79
+ } @empty { <p class="jc-muted">No service instances seen on it.</p> }
80
+ } @else {
81
+ <h2>Used by</h2>
82
+ @for (e of users(); track e.id) {
83
+ <div class="jc-list-row"><a [routerLink]="['services', e.source] | jcLink" [queryParams]="ctx.keep()">{{ name(e.source) }}</a>
84
+ <span>{{ e.relation }}</span><jc-confidence [confidence]="e.confidence" />
85
+ <a [routerLink]="['topology'] | jcLink" [queryParams]="ctx.keep({ edge: e.id })">evidence</a></div>
86
+ } @empty { <p class="jc-muted">No users seen{{ ctx.environment() ? ' in ' + ctx.environment() : '' }}.</p> }
87
+ }
88
+ </section>
89
+ </div>
90
+ @if (isInfrastructure()) {
91
+ <h2>Metrics</h2>
92
+ <jc-metric-explorer [scope]="{ resourceId: id() }" />
93
+ <h2>Logs</h2>
94
+ <jc-log-table [query]="{ resourceId: id() }" />
95
+ } @else {
96
+ <h2>Traces that reach it</h2>
97
+ <jc-trace-table [query]="{ resourceId: id() }" />
98
+ }
99
+ }`,
100
+ isInline: true,
101
+ dependencies: [
102
+ {
103
+ kind: "directive",
104
+ type: RouterLink,
105
+ selector: "[routerLink]",
106
+ inputs: [
107
+ "target",
108
+ "queryParams",
109
+ "fragment",
110
+ "queryParamsHandling",
111
+ "state",
112
+ "info",
113
+ "relativeTo",
114
+ "preserveFragment",
115
+ "skipLocationChange",
116
+ "replaceUrl",
117
+ "browserUrl",
118
+ "routerLink"
119
+ ]
120
+ },
121
+ {
122
+ kind: "ngmodule",
123
+ type: MatProgressBarModule
124
+ },
125
+ {
126
+ kind: "component",
127
+ type: i1.MatProgressBar,
128
+ selector: "mat-progress-bar",
129
+ inputs: [
130
+ "color",
131
+ "value",
132
+ "bufferValue",
133
+ "mode"
134
+ ],
135
+ outputs: ["animationEnd"],
136
+ exportAs: ["matProgressBar"]
137
+ },
138
+ {
139
+ kind: "component",
140
+ type: ContextBar,
141
+ selector: "jc-context-bar"
142
+ },
143
+ {
144
+ kind: "component",
145
+ type: HealthBadge,
146
+ selector: "jc-health",
147
+ inputs: ["state", "stale"]
148
+ },
149
+ {
150
+ kind: "component",
151
+ type: ConfidenceBadge,
152
+ selector: "jc-confidence",
153
+ inputs: ["confidence"]
154
+ },
155
+ {
156
+ kind: "component",
157
+ type: KeyValueTable,
158
+ selector: "jc-kv",
159
+ inputs: ["values", "empty"]
160
+ },
161
+ {
162
+ kind: "component",
163
+ type: TraceTable,
164
+ selector: "jc-trace-table",
165
+ inputs: ["query", "limit"]
166
+ },
167
+ {
168
+ kind: "component",
169
+ type: LogTable,
170
+ selector: "jc-log-table",
171
+ inputs: ["query", "compact"]
172
+ },
173
+ {
174
+ kind: "component",
175
+ type: MetricExplorer,
176
+ selector: "jc-metric-explorer",
177
+ inputs: ["scope", "initial"]
178
+ },
179
+ {
180
+ kind: "pipe",
181
+ type: LinkPipe,
182
+ name: "jcLink"
183
+ },
184
+ {
185
+ kind: "pipe",
186
+ type: AgoPipe,
187
+ name: "ago"
188
+ }
189
+ ],
190
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
191
+ });
192
+ };
193
+ i0.ɵɵngDeclareClassMetadata({
194
+ minVersion: "12.0.0",
195
+ version: "22.2.4",
196
+ ngImport: i0,
197
+ type: ResourcePage,
198
+ decorators: [{
199
+ type: Component,
200
+ args: [{
201
+ changeDetection: ChangeDetectionStrategy.OnPush,
202
+ imports: [
203
+ LinkPipe,
204
+ RouterLink,
205
+ MatProgressBarModule,
206
+ ContextBar,
207
+ HealthBadge,
208
+ ConfidenceBadge,
209
+ KeyValueTable,
210
+ TraceTable,
211
+ LogTable,
212
+ MetricExplorer,
213
+ AgoPipe
214
+ ],
215
+ template: `
216
+ <jc-context-bar>
217
+ <a [routerLink]="['resources'] | jcLink" [queryParams]="ctx.keep({ type: resource.value()?.type })" class="jc-crumb">Resources</a>
218
+ <span class="jc-crumb-sep">›</span>
219
+ <h1>{{ resource.value()?.displayName ?? '…' }}</h1>
220
+ <span class="jc-muted">{{ resource.value()?.type }}</span>
221
+ </jc-context-bar>
222
+ @if (resource.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
223
+ @if (resource.error()) { <p class="jc-error">{{ error() }}</p> }
224
+ @if (resource.value(); as r) {
225
+ <div class="jc-grid-2">
226
+ <section class="jc-card">
227
+ <h2>Identity</h2>
228
+ <jc-kv [values]="{ key: r.key, 'first seen': r.firstSeen, 'last seen': r.lastSeen }" />
229
+ <jc-kv [values]="r.attributes" empty="" />
230
+ @for (h of r.health; track h.subjectId) {
231
+ <p><jc-health [state]="h.state" [stale]="h.stale" /> {{ h.reasons.map(reason).join(' · ') }}</p>
232
+ }
233
+ </section>
234
+ <section class="jc-card">
235
+ @if (isInfrastructure()) {
236
+ <h2>Instances running here</h2>
237
+ @for (i of r.instances; track i.id) {
238
+ <div class="jc-list-row"><jc-health [state]="i.health" /><span>{{ i.instanceKey }}</span>
239
+ <span class="jc-muted">{{ i.environment }}</span><span class="jc-muted">{{ i.lastSeen | ago }}</span></div>
240
+ } @empty { <p class="jc-muted">No service instances seen on it.</p> }
241
+ } @else {
242
+ <h2>Used by</h2>
243
+ @for (e of users(); track e.id) {
244
+ <div class="jc-list-row"><a [routerLink]="['services', e.source] | jcLink" [queryParams]="ctx.keep()">{{ name(e.source) }}</a>
245
+ <span>{{ e.relation }}</span><jc-confidence [confidence]="e.confidence" />
246
+ <a [routerLink]="['topology'] | jcLink" [queryParams]="ctx.keep({ edge: e.id })">evidence</a></div>
247
+ } @empty { <p class="jc-muted">No users seen{{ ctx.environment() ? ' in ' + ctx.environment() : '' }}.</p> }
248
+ }
249
+ </section>
250
+ </div>
251
+ @if (isInfrastructure()) {
252
+ <h2>Metrics</h2>
253
+ <jc-metric-explorer [scope]="{ resourceId: id() }" />
254
+ <h2>Logs</h2>
255
+ <jc-log-table [query]="{ resourceId: id() }" />
256
+ } @else {
257
+ <h2>Traces that reach it</h2>
258
+ <jc-trace-table [query]="{ resourceId: id() }" />
259
+ }
260
+ }`
261
+ }]
262
+ }],
263
+ propDecorators: { id: [{
264
+ type: i0.Input,
265
+ args: [{
266
+ isSignal: true,
267
+ alias: "id",
268
+ required: true
269
+ }]
270
+ }] }
271
+ });
272
+ export { ResourcePage };
273
+
274
+ //# sourceMappingURL=juice-js-observability-resource.page-D6qpvo_f.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juice-js-observability-resource.page-D6qpvo_f.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":";;;;;;;AAkEA,IAAa,eAAb,MAAa,aAAY;CACJ,MAAM,OAAO,cAAc;CAC7B,MAAM,OAAO,UAAU;CAC/B,KAAK,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,KAAA,CAAA,+BAAA,CAAA,CAAA;CAEnB,WAAW,YAAY;EAAE,cAAc,KAAK,GAAE;EAAI,SAAS,EAAE,aAAa,KAAK,IAAI,SAAS,MAAM;CAAC,CAAE;CACrG,WAAW,YAAY;EAAE,cAAc,KAAK,IAAI,YAAW;EAAI,SAAS,EAAE,aAAa,KAAK,IAAI,SAAS,UAAU,IAAI;CAAC,CAAE;CAC1H,QAAQ,eAAe,YAAY,KAAK,SAAS,MAAK,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAC1D,mBAAmB,eAAe;EAAC;EAAQ;EAAa;CAAS,CAAC,CAAC,SAAS,KAAK,SAAS,MAAK,CAAE,EAAE,QAAQ,EAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CAC/G,QAAQ,gBAAgB,KAAK,SAAS,MAAK,CAAE,EAAE,SAAS,CAAA,EAAA,CAAI,QAAO,MAAK,EAAE,WAAW,KAAK,GAAE,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAClG,aAAa,IAAI,WAAU;CACzB,UAAU,MAAc,KAAK,WAAW,UAAU,CAAC;CAEtE,KAAK,IAAU;EAAI,OAAO,KAAK,SAAS,MAAK,CAAE,EAAE,MAAM,MAAK,MAAK,EAAE,OAAO,EAAE,CAAC,EAAE,eAAe;CAAI;CAbvF,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAY,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAZ,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAY,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,IAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,UAAA;EAAA,UA/Cb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6CN,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MA/CgB;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,MAAE;IAAW,UAAA;IAAA,QAAA,CAAA,SAAA,OAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAe,UAAA;IAAA,QAAA,CAAA,YAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAa,UAAA;IAAA,QAAA,CAAA,UAAA,OAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;IAAA,QAAA,CAAA,SAAA,OAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAQ,UAAA;IAAA,QAAA,CAAA,SAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACjI;IAAc,UAAA;IAAA,QAAA,CAAA,SAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MADN;IAAQ,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACA;IAAO,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAgDd,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAY,YAAA,CAAA;EAnDxB,MAAA;EAAU,MAAA,CAAA;GACT,iBAAiB,wBAAwB;GACzC,SAAS;IAAC;IAAU;IAAY;IAAsB;IAAY;IAAa;IAAiB;IAAe;IAAY;IACzH;IAAgB;GAAO;GACzB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CX,CAAA"}
@@ -0,0 +1,209 @@
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-D9EYxkdr.mjs";
3
+ import * as i0 from "@angular/core";
4
+ import { ChangeDetectionStrategy, Component, computed, inject, input, signal } from "@angular/core";
5
+ import { RouterLink } from "@angular/router";
6
+ import * as i2 from "@angular/material/progress-bar";
7
+ import { MatProgressBarModule } from "@angular/material/progress-bar";
8
+ import * as i1 from "@angular/material/paginator";
9
+ import { MatPaginatorModule } from "@angular/material/paginator";
10
+ const TYPES = [
11
+ "host",
12
+ "container",
13
+ "k8s-pod",
14
+ "database",
15
+ "messaging-destination"
16
+ ];
17
+ var ResourcesPage = class ResourcesPage {
18
+ ctx = inject(ContextService);
19
+ api = inject(ApiService);
20
+ types = TYPES;
21
+ type = input(...ngDevMode ? [void 0, { debugName: "type" }] : /* istanbul ignore next */ []);
22
+ filter = signal("", ...ngDevMode ? [{ debugName: "filter" }] : /* istanbul ignore next */ []);
23
+ resources = apiResource({
24
+ params: () => this.type() ?? "host",
25
+ stream: ({ params }) => this.api.resources(params)
26
+ });
27
+ error = computed(() => problemText(this.resources.error()), ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
28
+ capped = computed(() => (this.resources.value()?.nextCursor ?? null) !== null, ...ngDevMode ? [{ debugName: "capped" }] : /* istanbul ignore next */ []);
29
+ 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 */ []);
30
+ pages = screenPages(this.rows);
31
+ onSearch(query) {
32
+ this.filter.set(query);
33
+ }
34
+ static ɵfac = i0.ɵɵngDeclareFactory({
35
+ minVersion: "12.0.0",
36
+ version: "22.2.4",
37
+ ngImport: i0,
38
+ type: ResourcesPage,
39
+ deps: [],
40
+ target: i0.ɵɵFactoryTarget.Component
41
+ });
42
+ static ɵcmp = i0.ɵɵngDeclareComponent({
43
+ minVersion: "17.0.0",
44
+ version: "22.2.4",
45
+ type: ResourcesPage,
46
+ isStandalone: true,
47
+ selector: "ng-component",
48
+ inputs: { type: {
49
+ classPropertyName: "type",
50
+ publicName: "type",
51
+ isSignal: true,
52
+ isRequired: false,
53
+ transformFunction: null
54
+ } },
55
+ ngImport: i0,
56
+ template: `
57
+ <jc-context-bar><h1>Resources</h1>
58
+ @for (t of types; track t) {
59
+ <a class="jc-chip" [class.jc-selected]="t === (type() ?? 'host')" [routerLink]="['resources'] | jcLink" [queryParams]="ctx.keep({ type: t })">{{ t }}</a>
60
+ }
61
+ </jc-context-bar>
62
+ @if (resources.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
63
+ @if (resources.error()) { <p class="jc-error">{{ error() }}</p> }
64
+ @if (capped()) { <p class="jc-notice">Showing the first 5,000 only. Narrow the list with the search box or a filter.</p> }
65
+ <table class="jc-table">
66
+ <thead><tr><th>Name</th><th>Key</th><th>First seen</th><th>Last seen</th></tr></thead>
67
+ <tbody>
68
+ @for (r of pages.visible(); track r.id) {
69
+ <tr><td><a [routerLink]="['resources', r.id] | jcLink" [queryParams]="ctx.keep()">{{ r.displayName }}</a></td>
70
+ <td class="jc-mono jc-small">{{ r.key }}</td><td>{{ r.firstSeen | ago }}</td><td>{{ r.lastSeen | ago }}</td></tr>
71
+ } @empty { <tr><td colspan="4" class="jc-muted">None seen.</td></tr> }
72
+ </tbody>
73
+ </table>
74
+ @if (pages.needed()) {
75
+ <mat-paginator [length]="rows().length" [pageSize]="pages.size()" [pageIndex]="pages.index()" [pageSizeOptions]="pages.sizes"
76
+ (page)="pages.change($event)" aria-label="Pages" />
77
+ }`,
78
+ isInline: true,
79
+ dependencies: [
80
+ {
81
+ kind: "directive",
82
+ type: RouterLink,
83
+ selector: "[routerLink]",
84
+ inputs: [
85
+ "target",
86
+ "queryParams",
87
+ "fragment",
88
+ "queryParamsHandling",
89
+ "state",
90
+ "info",
91
+ "relativeTo",
92
+ "preserveFragment",
93
+ "skipLocationChange",
94
+ "replaceUrl",
95
+ "browserUrl",
96
+ "routerLink"
97
+ ]
98
+ },
99
+ {
100
+ kind: "ngmodule",
101
+ type: MatPaginatorModule
102
+ },
103
+ {
104
+ kind: "component",
105
+ type: i1.MatPaginator,
106
+ selector: "mat-paginator",
107
+ inputs: [
108
+ "color",
109
+ "pageIndex",
110
+ "length",
111
+ "pageSize",
112
+ "pageSizeOptions",
113
+ "hidePageSize",
114
+ "showFirstLastButtons",
115
+ "selectConfig",
116
+ "disabled"
117
+ ],
118
+ outputs: ["page"],
119
+ exportAs: ["matPaginator"]
120
+ },
121
+ {
122
+ kind: "ngmodule",
123
+ type: MatProgressBarModule
124
+ },
125
+ {
126
+ kind: "component",
127
+ type: i2.MatProgressBar,
128
+ selector: "mat-progress-bar",
129
+ inputs: [
130
+ "color",
131
+ "value",
132
+ "bufferValue",
133
+ "mode"
134
+ ],
135
+ outputs: ["animationEnd"],
136
+ exportAs: ["matProgressBar"]
137
+ },
138
+ {
139
+ kind: "component",
140
+ type: ContextBar,
141
+ selector: "jc-context-bar"
142
+ },
143
+ {
144
+ kind: "pipe",
145
+ type: LinkPipe,
146
+ name: "jcLink"
147
+ },
148
+ {
149
+ kind: "pipe",
150
+ type: AgoPipe,
151
+ name: "ago"
152
+ }
153
+ ],
154
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
155
+ });
156
+ };
157
+ i0.ɵɵngDeclareClassMetadata({
158
+ minVersion: "12.0.0",
159
+ version: "22.2.4",
160
+ ngImport: i0,
161
+ type: ResourcesPage,
162
+ decorators: [{
163
+ type: Component,
164
+ args: [{
165
+ changeDetection: ChangeDetectionStrategy.OnPush,
166
+ imports: [
167
+ LinkPipe,
168
+ RouterLink,
169
+ MatPaginatorModule,
170
+ MatProgressBarModule,
171
+ ContextBar,
172
+ AgoPipe
173
+ ],
174
+ template: `
175
+ <jc-context-bar><h1>Resources</h1>
176
+ @for (t of types; track t) {
177
+ <a class="jc-chip" [class.jc-selected]="t === (type() ?? 'host')" [routerLink]="['resources'] | jcLink" [queryParams]="ctx.keep({ type: t })">{{ t }}</a>
178
+ }
179
+ </jc-context-bar>
180
+ @if (resources.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
181
+ @if (resources.error()) { <p class="jc-error">{{ error() }}</p> }
182
+ @if (capped()) { <p class="jc-notice">Showing the first 5,000 only. Narrow the list with the search box or a filter.</p> }
183
+ <table class="jc-table">
184
+ <thead><tr><th>Name</th><th>Key</th><th>First seen</th><th>Last seen</th></tr></thead>
185
+ <tbody>
186
+ @for (r of pages.visible(); track r.id) {
187
+ <tr><td><a [routerLink]="['resources', r.id] | jcLink" [queryParams]="ctx.keep()">{{ r.displayName }}</a></td>
188
+ <td class="jc-mono jc-small">{{ r.key }}</td><td>{{ r.firstSeen | ago }}</td><td>{{ r.lastSeen | ago }}</td></tr>
189
+ } @empty { <tr><td colspan="4" class="jc-muted">None seen.</td></tr> }
190
+ </tbody>
191
+ </table>
192
+ @if (pages.needed()) {
193
+ <mat-paginator [length]="rows().length" [pageSize]="pages.size()" [pageIndex]="pages.index()" [pageSizeOptions]="pages.sizes"
194
+ (page)="pages.change($event)" aria-label="Pages" />
195
+ }`
196
+ }]
197
+ }],
198
+ propDecorators: { type: [{
199
+ type: i0.Input,
200
+ args: [{
201
+ isSignal: true,
202
+ alias: "type",
203
+ required: false
204
+ }]
205
+ }] }
206
+ });
207
+ export { ResourcesPage };
208
+
209
+ //# sourceMappingURL=juice-js-observability-resources.page-CR7-DFsh.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juice-js-observability-resources.page-CR7-DFsh.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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"}