@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.
- package/README.md +31 -2
- package/fesm2022/juice-js-observability-alert.page-D2OL0zTT.mjs +405 -0
- package/fesm2022/juice-js-observability-alert.page-D2OL0zTT.mjs.map +1 -0
- package/fesm2022/juice-js-observability-alerts.page-BLJvD_op.mjs +208 -0
- package/fesm2022/juice-js-observability-alerts.page-BLJvD_op.mjs.map +1 -0
- package/fesm2022/juice-js-observability-logs.page-BWFLleyX.mjs +414 -0
- package/fesm2022/juice-js-observability-logs.page-BWFLleyX.mjs.map +1 -0
- package/fesm2022/juice-js-observability-metrics.page-D1caPbQq.mjs +268 -0
- package/fesm2022/juice-js-observability-metrics.page-D1caPbQq.mjs.map +1 -0
- package/fesm2022/juice-js-observability-overview.page-UBwHjlyq.mjs +213 -0
- package/fesm2022/juice-js-observability-overview.page-UBwHjlyq.mjs.map +1 -0
- package/fesm2022/juice-js-observability-resource.page-BZwLK_vU.mjs +275 -0
- package/fesm2022/juice-js-observability-resource.page-BZwLK_vU.mjs.map +1 -0
- package/fesm2022/juice-js-observability-resources.page-C0xWOb5I.mjs +210 -0
- package/fesm2022/juice-js-observability-resources.page-C0xWOb5I.mjs.map +1 -0
- package/fesm2022/juice-js-observability-rules.page-Db_U5rRu.mjs +176 -0
- package/fesm2022/juice-js-observability-rules.page-Db_U5rRu.mjs.map +1 -0
- package/fesm2022/juice-js-observability-service.page-B-SWJ9I5.mjs +727 -0
- package/fesm2022/juice-js-observability-service.page-B-SWJ9I5.mjs.map +1 -0
- package/fesm2022/juice-js-observability-services.page-BmWgFnC8.mjs +252 -0
- package/fesm2022/juice-js-observability-services.page-BmWgFnC8.mjs.map +1 -0
- package/fesm2022/juice-js-observability-telemetry-VA4_3nzr.mjs +1748 -0
- package/fesm2022/juice-js-observability-telemetry-VA4_3nzr.mjs.map +1 -0
- package/fesm2022/juice-js-observability-topology.page-DEUNp10U.mjs +458 -0
- package/fesm2022/juice-js-observability-topology.page-DEUNp10U.mjs.map +1 -0
- package/fesm2022/juice-js-observability-trace.page-gBhMG2eQ.mjs +530 -0
- package/fesm2022/juice-js-observability-trace.page-gBhMG2eQ.mjs.map +1 -0
- package/fesm2022/juice-js-observability-traces.page-BCQg4V4o.mjs +521 -0
- package/fesm2022/juice-js-observability-traces.page-BCQg4V4o.mjs.map +1 -0
- package/fesm2022/juice-js-observability.mjs +396 -0
- package/fesm2022/juice-js-observability.mjs.map +1 -0
- package/package.json +48 -4
- package/styles/_observability.scss +133 -0
- 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":";;;;;;;;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,WAAW;EAAE,cAAc,KAAK,GAAE;EAAI,SAAS,EAAE,aAAa,KAAK,IAAI,SAAS,MAAM;CAAC,CAAE;CACpG,WAAW,WAAW;EAAE,cAAc,KAAK,IAAI,YAAW;EAAI,SAAS,EAAE,aAAa,KAAK,IAAI,SAAS,UAAU,IAAI;CAAC,CAAE;CACzH,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,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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"}
|