@juice-js/audit 0.0.0-stage → 1.0.0-alpha.2

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.
@@ -0,0 +1,282 @@
1
+ import { AuditApiService, AuditContextService, AuditLinkPipe } from "./juice-js-audit.mjs";
2
+ import { m as apiResource, p as problemText, r as AuditContextBar, t as AccessLogTable } from "./juice-js-audit-ui-DnfhiB6p.mjs";
3
+ import * as i0 from "@angular/core";
4
+ import { ChangeDetectionStrategy, Component, computed, inject } 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 OverviewPage = class OverviewPage {
9
+ api = inject(AuditApiService);
10
+ ctx = inject(AuditContextService);
11
+ overview = apiResource({
12
+ params: () => ({
13
+ range: this.ctx.range(),
14
+ abs: this.ctx.absolute()
15
+ }),
16
+ stream: () => this.api.overview(this.ctx.window())
17
+ });
18
+ error = computed(() => problemText(this.overview.error()), ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
19
+ share(item, all) {
20
+ return 100 * item.count / Math.max(1, ...all.map((a) => a.count));
21
+ }
22
+ tableOf(name) {
23
+ return name.includes(".") ? name.slice(name.lastIndexOf(".") + 1) : name;
24
+ }
25
+ static ɵfac = i0.ɵɵngDeclareFactory({
26
+ minVersion: "12.0.0",
27
+ version: "22.2.4",
28
+ ngImport: i0,
29
+ type: OverviewPage,
30
+ deps: [],
31
+ target: i0.ɵɵFactoryTarget.Component
32
+ });
33
+ static ɵcmp = i0.ɵɵngDeclareComponent({
34
+ minVersion: "17.0.0",
35
+ version: "22.2.4",
36
+ type: OverviewPage,
37
+ isStandalone: true,
38
+ selector: "ng-component",
39
+ ngImport: i0,
40
+ template: `
41
+ <ja-context-bar><h1>Audit</h1></ja-context-bar>
42
+ @if (overview.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
43
+ @if (overview.error()) { <p class="ja-error">{{ error() }}</p> }
44
+ @if (overview.value(); as o) {
45
+ <div class="ja-tiles">
46
+ <a class="ja-card ja-tile" [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep()"><span class="ja-muted">Access records</span><strong>{{ o.requests }}</strong></a>
47
+ <a class="ja-card ja-tile" [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ status: '4xx' })"><span class="ja-muted">Client errors (4xx)</span><strong [class.ja-warn]="o.clientErrors">{{ o.clientErrors }}</strong></a>
48
+ <a class="ja-card ja-tile" [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ status: '5xx' })"><span class="ja-muted">Server errors (5xx)</span><strong [class.ja-bad]="o.serverErrors">{{ o.serverErrors }}</strong></a>
49
+ <a class="ja-card ja-tile" [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ restricted: 'true' })"><span class="ja-muted">Restricted</span><strong>{{ o.restricted }}</strong></a>
50
+ <a class="ja-card ja-tile" [routerLink]="['data-changes'] | jaLink" [queryParams]="ctx.keep()"><span class="ja-muted">Data changes</span><strong>{{ o.dataChanges }}</strong></a>
51
+ </div>
52
+
53
+ <div class="ja-grid-3">
54
+ <section class="ja-card">
55
+ <h2>Status</h2>
56
+ @for (s of o.statuses; track s.name) {
57
+ <div class="ja-count">
58
+ <a [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep(s.name === 'other' ? {} : { status: s.name })">{{ s.name }}</a>
59
+ <span class="ja-count-bar"><i [class]="s.name.startsWith('5') ? 'ja-fill-bad' : s.name.startsWith('4') ? 'ja-fill-warn' : 'ja-fill-ok'" [style.width.%]="share(s, o.statuses)"></i></span>
60
+ <span>{{ s.count }}</span>
61
+ </div>
62
+ } @empty { <p class="ja-muted">No access records in this window.</p> }
63
+ </section>
64
+ <section class="ja-card">
65
+ <h2>Apps</h2>
66
+ @for (a of o.apps; track a.name) {
67
+ <div class="ja-count">
68
+ <a [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ app: a.name || null })">{{ a.name || '(none)' }}</a>
69
+ <span class="ja-count-bar"><i class="ja-fill-ok" [style.width.%]="share(a, o.apps)"></i></span>
70
+ <span>{{ a.count }}@if (a.errors) { <span class="ja-bad ja-small"> · {{ a.errors }} failed</span> }</span>
71
+ </div>
72
+ } @empty { <p class="ja-muted">None.</p> }
73
+ </section>
74
+ <section class="ja-card">
75
+ <h2>Users</h2>
76
+ @for (u of o.users; track u.name) {
77
+ <div class="ja-count">
78
+ @if (u.name) { <a [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ user: u.name })">{{ u.name }}</a> }
79
+ @else { <span class="ja-muted" title="Messages and background jobs run without a user">(no user)</span> }
80
+ <span class="ja-count-bar"><i class="ja-fill-ok" [style.width.%]="share(u, o.users)"></i></span>
81
+ <span>{{ u.count }}@if (u.errors) { <span class="ja-bad ja-small"> · {{ u.errors }} failed</span> }</span>
82
+ </div>
83
+ } @empty { <p class="ja-muted">None.</p> }
84
+ </section>
85
+ </div>
86
+
87
+ <div class="ja-grid-2">
88
+ <section class="ja-card">
89
+ <h2>Changed tables</h2>
90
+ @for (t of o.tables; track t.name) {
91
+ <div class="ja-count">
92
+ <a class="ja-mono" [routerLink]="['data-changes'] | jaLink" [queryParams]="ctx.keep({ table: tableOf(t.name) })">{{ t.name }}</a>
93
+ <span class="ja-count-bar"><i class="ja-fill-info" [style.width.%]="share(t, o.tables)"></i></span>
94
+ <span>{{ t.count }}</span>
95
+ </div>
96
+ } @empty { <p class="ja-muted">No data changed in this window.</p> }
97
+ </section>
98
+ <section class="ja-card">
99
+ <h2>Changes</h2>
100
+ @for (a of o.changeActions; track a.name) {
101
+ <div class="ja-count">
102
+ <a [routerLink]="['data-changes'] | jaLink" [queryParams]="ctx.keep({ action: a.name })">{{ a.name }}</a>
103
+ <span class="ja-count-bar"><i class="ja-fill-info" [style.width.%]="share(a, o.changeActions)"></i></span>
104
+ <span>{{ a.count }}</span>
105
+ </div>
106
+ } @empty { <p class="ja-muted">None.</p> }
107
+ </section>
108
+ </div>
109
+
110
+ <section class="ja-card">
111
+ <div class="ja-row"><h2>Latest failures</h2><a [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ status: 'error' })">All failures</a></div>
112
+ @if (o.recentErrors.length) { <ja-access-log-table [rows]="o.recentErrors" /> }
113
+ @else { <p class="ja-muted">No failed requests in this window.</p> }
114
+ </section>
115
+ <section class="ja-card">
116
+ <h2>Slowest</h2>
117
+ @if (o.slowest.length) { <ja-access-log-table [rows]="o.slowest" /> }
118
+ @else { <p class="ja-muted">No timed requests in this window.</p> }
119
+ </section>
120
+ }`,
121
+ isInline: true,
122
+ dependencies: [
123
+ {
124
+ kind: "directive",
125
+ type: RouterLink,
126
+ selector: "[routerLink]",
127
+ inputs: [
128
+ "target",
129
+ "queryParams",
130
+ "fragment",
131
+ "queryParamsHandling",
132
+ "state",
133
+ "info",
134
+ "relativeTo",
135
+ "preserveFragment",
136
+ "skipLocationChange",
137
+ "replaceUrl",
138
+ "browserUrl",
139
+ "routerLink"
140
+ ]
141
+ },
142
+ {
143
+ kind: "ngmodule",
144
+ type: MatProgressBarModule
145
+ },
146
+ {
147
+ kind: "component",
148
+ type: i1.MatProgressBar,
149
+ selector: "mat-progress-bar",
150
+ inputs: [
151
+ "color",
152
+ "value",
153
+ "bufferValue",
154
+ "mode"
155
+ ],
156
+ outputs: ["animationEnd"],
157
+ exportAs: ["matProgressBar"]
158
+ },
159
+ {
160
+ kind: "component",
161
+ type: AuditContextBar,
162
+ selector: "ja-context-bar",
163
+ inputs: ["showRange"]
164
+ },
165
+ {
166
+ kind: "component",
167
+ type: AccessLogTable,
168
+ selector: "ja-access-log-table",
169
+ inputs: ["rows", "compact"]
170
+ },
171
+ {
172
+ kind: "pipe",
173
+ type: AuditLinkPipe,
174
+ name: "jaLink"
175
+ }
176
+ ],
177
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
178
+ });
179
+ };
180
+ i0.ɵɵngDeclareClassMetadata({
181
+ minVersion: "12.0.0",
182
+ version: "22.2.4",
183
+ ngImport: i0,
184
+ type: OverviewPage,
185
+ decorators: [{
186
+ type: Component,
187
+ args: [{
188
+ changeDetection: ChangeDetectionStrategy.OnPush,
189
+ imports: [
190
+ RouterLink,
191
+ MatProgressBarModule,
192
+ AuditLinkPipe,
193
+ AuditContextBar,
194
+ AccessLogTable
195
+ ],
196
+ template: `
197
+ <ja-context-bar><h1>Audit</h1></ja-context-bar>
198
+ @if (overview.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
199
+ @if (overview.error()) { <p class="ja-error">{{ error() }}</p> }
200
+ @if (overview.value(); as o) {
201
+ <div class="ja-tiles">
202
+ <a class="ja-card ja-tile" [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep()"><span class="ja-muted">Access records</span><strong>{{ o.requests }}</strong></a>
203
+ <a class="ja-card ja-tile" [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ status: '4xx' })"><span class="ja-muted">Client errors (4xx)</span><strong [class.ja-warn]="o.clientErrors">{{ o.clientErrors }}</strong></a>
204
+ <a class="ja-card ja-tile" [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ status: '5xx' })"><span class="ja-muted">Server errors (5xx)</span><strong [class.ja-bad]="o.serverErrors">{{ o.serverErrors }}</strong></a>
205
+ <a class="ja-card ja-tile" [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ restricted: 'true' })"><span class="ja-muted">Restricted</span><strong>{{ o.restricted }}</strong></a>
206
+ <a class="ja-card ja-tile" [routerLink]="['data-changes'] | jaLink" [queryParams]="ctx.keep()"><span class="ja-muted">Data changes</span><strong>{{ o.dataChanges }}</strong></a>
207
+ </div>
208
+
209
+ <div class="ja-grid-3">
210
+ <section class="ja-card">
211
+ <h2>Status</h2>
212
+ @for (s of o.statuses; track s.name) {
213
+ <div class="ja-count">
214
+ <a [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep(s.name === 'other' ? {} : { status: s.name })">{{ s.name }}</a>
215
+ <span class="ja-count-bar"><i [class]="s.name.startsWith('5') ? 'ja-fill-bad' : s.name.startsWith('4') ? 'ja-fill-warn' : 'ja-fill-ok'" [style.width.%]="share(s, o.statuses)"></i></span>
216
+ <span>{{ s.count }}</span>
217
+ </div>
218
+ } @empty { <p class="ja-muted">No access records in this window.</p> }
219
+ </section>
220
+ <section class="ja-card">
221
+ <h2>Apps</h2>
222
+ @for (a of o.apps; track a.name) {
223
+ <div class="ja-count">
224
+ <a [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ app: a.name || null })">{{ a.name || '(none)' }}</a>
225
+ <span class="ja-count-bar"><i class="ja-fill-ok" [style.width.%]="share(a, o.apps)"></i></span>
226
+ <span>{{ a.count }}@if (a.errors) { <span class="ja-bad ja-small"> · {{ a.errors }} failed</span> }</span>
227
+ </div>
228
+ } @empty { <p class="ja-muted">None.</p> }
229
+ </section>
230
+ <section class="ja-card">
231
+ <h2>Users</h2>
232
+ @for (u of o.users; track u.name) {
233
+ <div class="ja-count">
234
+ @if (u.name) { <a [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ user: u.name })">{{ u.name }}</a> }
235
+ @else { <span class="ja-muted" title="Messages and background jobs run without a user">(no user)</span> }
236
+ <span class="ja-count-bar"><i class="ja-fill-ok" [style.width.%]="share(u, o.users)"></i></span>
237
+ <span>{{ u.count }}@if (u.errors) { <span class="ja-bad ja-small"> · {{ u.errors }} failed</span> }</span>
238
+ </div>
239
+ } @empty { <p class="ja-muted">None.</p> }
240
+ </section>
241
+ </div>
242
+
243
+ <div class="ja-grid-2">
244
+ <section class="ja-card">
245
+ <h2>Changed tables</h2>
246
+ @for (t of o.tables; track t.name) {
247
+ <div class="ja-count">
248
+ <a class="ja-mono" [routerLink]="['data-changes'] | jaLink" [queryParams]="ctx.keep({ table: tableOf(t.name) })">{{ t.name }}</a>
249
+ <span class="ja-count-bar"><i class="ja-fill-info" [style.width.%]="share(t, o.tables)"></i></span>
250
+ <span>{{ t.count }}</span>
251
+ </div>
252
+ } @empty { <p class="ja-muted">No data changed in this window.</p> }
253
+ </section>
254
+ <section class="ja-card">
255
+ <h2>Changes</h2>
256
+ @for (a of o.changeActions; track a.name) {
257
+ <div class="ja-count">
258
+ <a [routerLink]="['data-changes'] | jaLink" [queryParams]="ctx.keep({ action: a.name })">{{ a.name }}</a>
259
+ <span class="ja-count-bar"><i class="ja-fill-info" [style.width.%]="share(a, o.changeActions)"></i></span>
260
+ <span>{{ a.count }}</span>
261
+ </div>
262
+ } @empty { <p class="ja-muted">None.</p> }
263
+ </section>
264
+ </div>
265
+
266
+ <section class="ja-card">
267
+ <div class="ja-row"><h2>Latest failures</h2><a [routerLink]="['access-logs'] | jaLink" [queryParams]="ctx.keep({ status: 'error' })">All failures</a></div>
268
+ @if (o.recentErrors.length) { <ja-access-log-table [rows]="o.recentErrors" /> }
269
+ @else { <p class="ja-muted">No failed requests in this window.</p> }
270
+ </section>
271
+ <section class="ja-card">
272
+ <h2>Slowest</h2>
273
+ @if (o.slowest.length) { <ja-access-log-table [rows]="o.slowest" /> }
274
+ @else { <p class="ja-muted">No timed requests in this window.</p> }
275
+ </section>
276
+ }`
277
+ }]
278
+ }]
279
+ });
280
+ export { OverviewPage };
281
+
282
+ //# sourceMappingURL=juice-js-audit-overview.page-DnP722u2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juice-js-audit-overview.page-DnP722u2.mjs","names":[],"sources":["../../../../projects/juice-js/audit/src/lib/pages/overview.page.ts"],"sourcesContent":["import { 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 { AuditApiService } from '../core/api.service';\nimport { AuditContextService } from '../core/context.service';\nimport { AuditCount } from '../core/models';\nimport { AuditLinkPipe } from '../core/options';\nimport { problemText } from '../shared/format';\nimport { AccessLogTable, AuditContextBar } from '../shared/ui';\n\n/**\n * The window at a glance: how much was audited, how much failed, who and which apps, which tables changed; then the\n * latest failures and the slowest requests. Every count opens the list it counts.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [RouterLink, MatProgressBarModule, AuditLinkPipe, AuditContextBar, AccessLogTable],\n template: `\n <ja-context-bar><h1>Audit</h1></ja-context-bar>\n @if (overview.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (overview.error()) { <p class=\"ja-error\">{{ error() }}</p> }\n @if (overview.value(); as o) {\n <div class=\"ja-tiles\">\n <a class=\"ja-card ja-tile\" [routerLink]=\"['access-logs'] | jaLink\" [queryParams]=\"ctx.keep()\"><span class=\"ja-muted\">Access records</span><strong>{{ o.requests }}</strong></a>\n <a class=\"ja-card ja-tile\" [routerLink]=\"['access-logs'] | jaLink\" [queryParams]=\"ctx.keep({ status: '4xx' })\"><span class=\"ja-muted\">Client errors (4xx)</span><strong [class.ja-warn]=\"o.clientErrors\">{{ o.clientErrors }}</strong></a>\n <a class=\"ja-card ja-tile\" [routerLink]=\"['access-logs'] | jaLink\" [queryParams]=\"ctx.keep({ status: '5xx' })\"><span class=\"ja-muted\">Server errors (5xx)</span><strong [class.ja-bad]=\"o.serverErrors\">{{ o.serverErrors }}</strong></a>\n <a class=\"ja-card ja-tile\" [routerLink]=\"['access-logs'] | jaLink\" [queryParams]=\"ctx.keep({ restricted: 'true' })\"><span class=\"ja-muted\">Restricted</span><strong>{{ o.restricted }}</strong></a>\n <a class=\"ja-card ja-tile\" [routerLink]=\"['data-changes'] | jaLink\" [queryParams]=\"ctx.keep()\"><span class=\"ja-muted\">Data changes</span><strong>{{ o.dataChanges }}</strong></a>\n </div>\n\n <div class=\"ja-grid-3\">\n <section class=\"ja-card\">\n <h2>Status</h2>\n @for (s of o.statuses; track s.name) {\n <div class=\"ja-count\">\n <a [routerLink]=\"['access-logs'] | jaLink\" [queryParams]=\"ctx.keep(s.name === 'other' ? {} : { status: s.name })\">{{ s.name }}</a>\n <span class=\"ja-count-bar\"><i [class]=\"s.name.startsWith('5') ? 'ja-fill-bad' : s.name.startsWith('4') ? 'ja-fill-warn' : 'ja-fill-ok'\" [style.width.%]=\"share(s, o.statuses)\"></i></span>\n <span>{{ s.count }}</span>\n </div>\n } @empty { <p class=\"ja-muted\">No access records in this window.</p> }\n </section>\n <section class=\"ja-card\">\n <h2>Apps</h2>\n @for (a of o.apps; track a.name) {\n <div class=\"ja-count\">\n <a [routerLink]=\"['access-logs'] | jaLink\" [queryParams]=\"ctx.keep({ app: a.name || null })\">{{ a.name || '(none)' }}</a>\n <span class=\"ja-count-bar\"><i class=\"ja-fill-ok\" [style.width.%]=\"share(a, o.apps)\"></i></span>\n <span>{{ a.count }}@if (a.errors) { <span class=\"ja-bad ja-small\"> · {{ a.errors }} failed</span> }</span>\n </div>\n } @empty { <p class=\"ja-muted\">None.</p> }\n </section>\n <section class=\"ja-card\">\n <h2>Users</h2>\n @for (u of o.users; track u.name) {\n <div class=\"ja-count\">\n @if (u.name) { <a [routerLink]=\"['access-logs'] | jaLink\" [queryParams]=\"ctx.keep({ user: u.name })\">{{ u.name }}</a> }\n @else { <span class=\"ja-muted\" title=\"Messages and background jobs run without a user\">(no user)</span> }\n <span class=\"ja-count-bar\"><i class=\"ja-fill-ok\" [style.width.%]=\"share(u, o.users)\"></i></span>\n <span>{{ u.count }}@if (u.errors) { <span class=\"ja-bad ja-small\"> · {{ u.errors }} failed</span> }</span>\n </div>\n } @empty { <p class=\"ja-muted\">None.</p> }\n </section>\n </div>\n\n <div class=\"ja-grid-2\">\n <section class=\"ja-card\">\n <h2>Changed tables</h2>\n @for (t of o.tables; track t.name) {\n <div class=\"ja-count\">\n <a class=\"ja-mono\" [routerLink]=\"['data-changes'] | jaLink\" [queryParams]=\"ctx.keep({ table: tableOf(t.name) })\">{{ t.name }}</a>\n <span class=\"ja-count-bar\"><i class=\"ja-fill-info\" [style.width.%]=\"share(t, o.tables)\"></i></span>\n <span>{{ t.count }}</span>\n </div>\n } @empty { <p class=\"ja-muted\">No data changed in this window.</p> }\n </section>\n <section class=\"ja-card\">\n <h2>Changes</h2>\n @for (a of o.changeActions; track a.name) {\n <div class=\"ja-count\">\n <a [routerLink]=\"['data-changes'] | jaLink\" [queryParams]=\"ctx.keep({ action: a.name })\">{{ a.name }}</a>\n <span class=\"ja-count-bar\"><i class=\"ja-fill-info\" [style.width.%]=\"share(a, o.changeActions)\"></i></span>\n <span>{{ a.count }}</span>\n </div>\n } @empty { <p class=\"ja-muted\">None.</p> }\n </section>\n </div>\n\n <section class=\"ja-card\">\n <div class=\"ja-row\"><h2>Latest failures</h2><a [routerLink]=\"['access-logs'] | jaLink\" [queryParams]=\"ctx.keep({ status: 'error' })\">All failures</a></div>\n @if (o.recentErrors.length) { <ja-access-log-table [rows]=\"o.recentErrors\" /> }\n @else { <p class=\"ja-muted\">No failed requests in this window.</p> }\n </section>\n <section class=\"ja-card\">\n <h2>Slowest</h2>\n @if (o.slowest.length) { <ja-access-log-table [rows]=\"o.slowest\" /> }\n @else { <p class=\"ja-muted\">No timed requests in this window.</p> }\n </section>\n }`,\n})\nexport class OverviewPage {\n private readonly api = inject(AuditApiService);\n protected readonly ctx = inject(AuditContextService);\n\n protected readonly overview = apiResource({\n params: () => ({ range: this.ctx.range(), abs: this.ctx.absolute() }),\n stream: () => this.api.overview(this.ctx.window()),\n });\n protected readonly error = computed(() => problemText(this.overview.error()));\n\n share(item: AuditCount, all: AuditCount[]) { return 100 * item.count / Math.max(1, ...all.map(a => a.count)); }\n\n /** `schema.table` → `table`: the list filters on the table name. */\n tableOf(name: string) { return name.includes('.') ? name.slice(name.lastIndexOf('.') + 1) : name; }\n}\n"],"mappings":";;;;;;;AAoGA,IAAa,eAAb,MAAa,aAAY;CACN,MAAM,OAAO,eAAe;CAC1B,MAAM,OAAO,mBAAmB;CAEhC,WAAW,YAAY;EACxC,eAAe;GAAE,OAAO,KAAK,IAAI,MAAK;GAAI,KAAK,KAAK,IAAI,SAAQ;EAAE;EAClE,cAAc,KAAK,IAAI,SAAS,KAAK,IAAI,OAAM,CAAE;CAClD,CAAA;CACkB,QAAQ,eAAe,YAAY,KAAK,SAAS,MAAK,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAE7E,MAAM,MAAkB,KAAiB;EAAI,OAAO,MAAM,KAAK,QAAQ,KAAK,IAAI,GAAG,GAAG,IAAI,KAAI,MAAK,EAAE,KAAK,CAAC;CAAG;CAG9G,QAAQ,MAAY;EAAI,OAAO,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,KAAK,YAAY,GAAG,IAAI,CAAC,IAAI;CAAM;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,UAAA;EAAA,UAlFb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgFN,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAjFM;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,MAAiB;IAAe,UAAA;IAAA,QAAA,CAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAc,UAAA;IAAA,QAAA,CAAA,QAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAA9C;IAAa,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAmF9C,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAY,YAAA,CAAA;EArFxB,MAAA;EAAU,MAAA,CAAA;GACT,iBAAiB,wBAAwB;GACzC,SAAS;IAAC;IAAY;IAAsB;IAAe;IAAiB;GAAc;GAC1F,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiFX,CAAA"}
@@ -0,0 +1,61 @@
1
+ import { m as apiResource } from "./juice-js-audit-ui-DnfhiB6p.mjs";
2
+ import { DestroyRef, computed, inject, linkedSignal, signal } from "@angular/core";
3
+ import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
4
+ import { map } from "rxjs";
5
+ function cursorList(params, query, fetch) {
6
+ const destroyRef = inject(DestroyRef);
7
+ const first = apiResource({
8
+ params,
9
+ stream: ({ params }) => {
10
+ const q = query(params);
11
+ return fetch(q).pipe(map((page) => ({
12
+ page,
13
+ query: q
14
+ })));
15
+ }
16
+ });
17
+ const rest = linkedSignal({
18
+ ...ngDevMode ? { debugName: "rest" } : /* istanbul ignore next */ {},
19
+ source: first.value,
20
+ computation: () => ({
21
+ items: [],
22
+ cursor: void 0
23
+ })
24
+ });
25
+ const loadingMore = signal(false, ...ngDevMode ? [{ debugName: "loadingMore" }] : /* istanbul ignore next */ []);
26
+ const moreError = signal(null, ...ngDevMode ? [{ debugName: "moreError" }] : /* istanbul ignore next */ []);
27
+ const items = computed(() => [...first.value()?.page.items ?? [], ...rest().items], ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
28
+ const cursor = computed(() => rest().cursor !== void 0 ? rest().cursor : first.value()?.page.nextCursor ?? null, ...ngDevMode ? [{ debugName: "cursor" }] : /* istanbul ignore next */ []);
29
+ function more() {
30
+ const current = first.value();
31
+ const next = cursor();
32
+ if (!current || !next || loadingMore()) return;
33
+ loadingMore.set(true);
34
+ moreError.set(null);
35
+ fetch({
36
+ ...current.query,
37
+ cursor: next
38
+ }).pipe(takeUntilDestroyed(destroyRef)).subscribe({
39
+ next: (page) => rest.update((r) => ({
40
+ items: [...r.items, ...page.items],
41
+ cursor: page.nextCursor ?? null
42
+ })),
43
+ error: (e) => {
44
+ moreError.set(e);
45
+ loadingMore.set(false);
46
+ },
47
+ complete: () => loadingMore.set(false)
48
+ });
49
+ }
50
+ return {
51
+ first,
52
+ items,
53
+ hasMore: computed(() => cursor() !== null),
54
+ loadingMore,
55
+ moreError: moreError.asReadonly(),
56
+ more
57
+ };
58
+ }
59
+ export { cursorList as t };
60
+
61
+ //# sourceMappingURL=juice-js-audit-paging-D5-1J1rG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juice-js-audit-paging-D5-1J1rG.mjs","names":[],"sources":["../../../../projects/juice-js/audit/src/lib/shared/paging.ts"],"sourcesContent":["import { DestroyRef, computed, inject, linkedSignal, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { apiResource } from './resource';\nimport { Observable, map } from 'rxjs';\nimport { AuditQuery } from '../core/api.service';\nimport { AuditPage } from '../core/models';\n\n/**\n * A newest-first list read page by page with the API's cursor. The first page loads whenever `params` change; `more()`\n * appends the next page, asked with exactly the query of the first one (its time window included), so the list grows\n * without shifting, skipping or repeating rows. Call it in an injection context, such as a field initializer.\n */\nexport function cursorList<P, T>(params: () => P, query: (params: P) => AuditQuery, fetch: (query: AuditQuery) => Observable<AuditPage<T>>) {\n const destroyRef = inject(DestroyRef);\n const first = apiResource({\n params,\n stream: ({ params }) => {\n const q = query(params);\n return fetch(q).pipe(map(page => ({ page, query: q })));\n },\n });\n // Pages after the first; reset whenever the first page reloads.\n const rest = linkedSignal({ source: first.value, computation: () => ({ items: [] as T[], cursor: undefined as string | null | undefined }) });\n const loadingMore = signal(false);\n const moreError = signal<unknown>(null);\n const items = computed(() => [...(first.value()?.page.items ?? []), ...rest().items]);\n const cursor = computed(() => rest().cursor !== undefined ? rest().cursor! : first.value()?.page.nextCursor ?? null);\n\n function more() {\n const current = first.value();\n const next = cursor();\n if (!current || !next || loadingMore()) return;\n loadingMore.set(true);\n moreError.set(null);\n fetch({ ...current.query, cursor: next }).pipe(takeUntilDestroyed(destroyRef)).subscribe({\n next: page => rest.update(r => ({ items: [...r.items, ...page.items], cursor: page.nextCursor ?? null })),\n error: e => { moreError.set(e); loadingMore.set(false); },\n complete: () => loadingMore.set(false),\n });\n }\n\n return { first, items, hasMore: computed(() => cursor() !== null), loadingMore, moreError: moreError.asReadonly(), more };\n}\n"],"mappings":";;;;AAYA,SAAgB,WAAiB,QAAiB,OAAkC,OAAsD;CACxI,MAAM,aAAa,OAAO,UAAU;CACpC,MAAM,QAAQ,YAAY;EACxB;EACA,SAAS,EAAE,aAAY;GACrB,MAAM,IAAI,MAAM,MAAM;GACtB,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,KAAI,UAAS;IAAE;IAAM,OAAO;GAAC,EAAG,CAAC;EACxD;CACD,CAAA;CAED,MAAM,OAAO,aAAY;EAAA,GAAA,YAAA,EAAA,WAAA,OAAA,+BAAA,CAAA;EAAG,QAAQ,MAAM;EAAO,oBAAoB;GAAE,OAAO,CAAA;GAAW,QAAQ;EAAsC;CAAG,CAAA;CAC1I,MAAM,cAAc,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CACjC,MAAM,YAAY,OAAgB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CACvC,MAAM,QAAQ,eAAe,CAAC,GAAI,MAAM,MAAK,CAAE,EAAE,KAAK,SAAS,CAAA,GAAK,GAAG,KAAI,CAAE,CAAC,KAAK,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACrF,MAAM,SAAS,eAAe,KAAI,CAAE,CAAC,WAAW,SAAY,KAAI,CAAE,CAAC,SAAU,MAAM,MAAK,CAAE,EAAE,KAAK,cAAc,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAEpH,SAAS,OAAI;EACX,MAAM,UAAU,MAAM,MAAK;EAC3B,MAAM,OAAO,OAAM;EACnB,IAAI,CAAC,WAAW,CAAC,QAAQ,YAAW,GAAI;EACxC,YAAY,IAAI,IAAI;EACpB,UAAU,IAAI,IAAI;EAClB,MAAM;GAAE,GAAG,QAAQ;GAAO,QAAQ;EAAI,CAAE,CAAC,CAAC,KAAK,mBAAmB,UAAU,CAAC,CAAC,CAAC,UAAU;GACvF,OAAM,SAAQ,KAAK,QAAO,OAAM;IAAE,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,KAAK;IAAG,QAAQ,KAAK,cAAc;GAAI,EAAG;GACxG,QAAO,MAAI;IAAG,UAAU,IAAI,CAAC;IAAG,YAAY,IAAI,KAAK;GAAG;GACxD,gBAAgB,YAAY,IAAI,KAAK;EACtC,CAAA;CACH;CAEA,OAAO;EAAE;EAAO;EAAO,SAAS,eAAe,OAAM,MAAO,IAAI;EAAG;EAAa,WAAW,UAAU,WAAU;EAAI;CAAI;AACzH"}
@@ -0,0 +1,229 @@
1
+ import { AuditApiService, AuditContextService, AuditLinkPipe, AuditLinks, accessLogSummary } from "./juice-js-audit.mjs";
2
+ import { i as ChangeDiff, m as apiResource, n as ActionBadge, p as problemText, r as AuditContextBar, t as AccessLogTable, u as KeysPipe } from "./juice-js-audit-ui-DnfhiB6p.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 { DatePipe } from "@angular/common";
7
+ import * as i1 from "@angular/material/progress-bar";
8
+ import { MatProgressBarModule } from "@angular/material/progress-bar";
9
+ var TracePage = class TracePage {
10
+ api = inject(AuditApiService);
11
+ links = inject(AuditLinks);
12
+ ctx = inject(AuditContextService);
13
+ traceId = input.required(...ngDevMode ? [{ debugName: "traceId" }] : /* istanbul ignore next */ []);
14
+ trace = apiResource({
15
+ params: () => this.traceId(),
16
+ stream: ({ params }) => this.api.trace(params)
17
+ });
18
+ external = computed(() => this.links.externalTrace(this.trace.value()?.traceId ?? this.traceId()), ...ngDevMode ? [{ debugName: "external" }] : /* istanbul ignore next */ []);
19
+ accessLogs = computed(() => (this.trace.value()?.accessLogs ?? []).map(accessLogSummary), ...ngDevMode ? [{ debugName: "accessLogs" }] : /* istanbul ignore next */ []);
20
+ error = computed(() => problemText(this.trace.error()), ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
21
+ static ɵfac = i0.ɵɵngDeclareFactory({
22
+ minVersion: "12.0.0",
23
+ version: "22.2.4",
24
+ ngImport: i0,
25
+ type: TracePage,
26
+ deps: [],
27
+ target: i0.ɵɵFactoryTarget.Component
28
+ });
29
+ static ɵcmp = i0.ɵɵngDeclareComponent({
30
+ minVersion: "17.0.0",
31
+ version: "22.2.4",
32
+ type: TracePage,
33
+ isStandalone: true,
34
+ selector: "ng-component",
35
+ inputs: { traceId: {
36
+ classPropertyName: "traceId",
37
+ publicName: "traceId",
38
+ isSignal: true,
39
+ isRequired: true,
40
+ transformFunction: null
41
+ } },
42
+ ngImport: i0,
43
+ template: `
44
+ <ja-context-bar [showRange]="false"><h1>Trace <span class="ja-mono ja-h-id">{{ traceId() }}</span></h1></ja-context-bar>
45
+ @if (external(); as x) {
46
+ <p>@if ('href' in x) { <a [href]="x.href" target="_blank" rel="noopener">Open its spans and logs ↗</a> }
47
+ @else { <a [routerLink]="x.route">Open its spans and logs ↗</a> }</p>
48
+ }
49
+ @if (trace.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
50
+ @if (trace.error()) { <p class="ja-error">{{ error() }}</p> }
51
+ @if (trace.value(); as t) {
52
+ @if (t.accessLogs.length === 0 && t.dataChanges.length === 0) {
53
+ <p class="ja-muted">Nothing was audited under this trace id.</p>
54
+ }
55
+ @if (t.truncated) { <p class="ja-notice">This trace has more records than the {{ t.accessLogs.length }} access records and {{ t.dataChanges.length }} changes shown.</p> }
56
+ @if (t.accessLogs.length) {
57
+ <section class="ja-card">
58
+ <h2>Access records ({{ t.accessLogs.length }})</h2>
59
+ <ja-access-log-table [rows]="accessLogs()" />
60
+ </section>
61
+ }
62
+ @if (t.dataChanges.length) {
63
+ <h2>Data changes ({{ t.dataChanges.length }})</h2>
64
+ @for (c of t.dataChanges; track c.id) {
65
+ <section class="ja-card">
66
+ <div class="ja-row">
67
+ <span class="ja-summary">
68
+ <ja-action [action]="c.action" />
69
+ <a class="ja-mono" [routerLink]="['data-changes', c.id] | jaLink" [queryParams]="ctx.keep()">{{ c.schema ? c.schema + '.' : '' }}{{ c.table }}</a>
70
+ <span class="ja-mono ja-small">{{ c.keys | jaKeys }}</span>
71
+ </span>
72
+ <span class="ja-muted ja-small">{{ c.dateTime | date: 'HH:mm:ss.SSS' }} · {{ c.user || 'no user' }}</span>
73
+ </div>
74
+ <ja-change-diff [changes]="c.changes" />
75
+ </section>
76
+ }
77
+ }
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: MatProgressBarModule
103
+ },
104
+ {
105
+ kind: "component",
106
+ type: i1.MatProgressBar,
107
+ selector: "mat-progress-bar",
108
+ inputs: [
109
+ "color",
110
+ "value",
111
+ "bufferValue",
112
+ "mode"
113
+ ],
114
+ outputs: ["animationEnd"],
115
+ exportAs: ["matProgressBar"]
116
+ },
117
+ {
118
+ kind: "component",
119
+ type: AuditContextBar,
120
+ selector: "ja-context-bar",
121
+ inputs: ["showRange"]
122
+ },
123
+ {
124
+ kind: "component",
125
+ type: AccessLogTable,
126
+ selector: "ja-access-log-table",
127
+ inputs: ["rows", "compact"]
128
+ },
129
+ {
130
+ kind: "component",
131
+ type: ActionBadge,
132
+ selector: "ja-action",
133
+ inputs: ["action"]
134
+ },
135
+ {
136
+ kind: "component",
137
+ type: ChangeDiff,
138
+ selector: "ja-change-diff",
139
+ inputs: ["changes"]
140
+ },
141
+ {
142
+ kind: "pipe",
143
+ type: DatePipe,
144
+ name: "date"
145
+ },
146
+ {
147
+ kind: "pipe",
148
+ type: AuditLinkPipe,
149
+ name: "jaLink"
150
+ },
151
+ {
152
+ kind: "pipe",
153
+ type: KeysPipe,
154
+ name: "jaKeys"
155
+ }
156
+ ],
157
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
158
+ });
159
+ };
160
+ i0.ɵɵngDeclareClassMetadata({
161
+ minVersion: "12.0.0",
162
+ version: "22.2.4",
163
+ ngImport: i0,
164
+ type: TracePage,
165
+ decorators: [{
166
+ type: Component,
167
+ args: [{
168
+ changeDetection: ChangeDetectionStrategy.OnPush,
169
+ imports: [
170
+ RouterLink,
171
+ DatePipe,
172
+ MatProgressBarModule,
173
+ AuditLinkPipe,
174
+ KeysPipe,
175
+ AuditContextBar,
176
+ AccessLogTable,
177
+ ActionBadge,
178
+ ChangeDiff
179
+ ],
180
+ template: `
181
+ <ja-context-bar [showRange]="false"><h1>Trace <span class="ja-mono ja-h-id">{{ traceId() }}</span></h1></ja-context-bar>
182
+ @if (external(); as x) {
183
+ <p>@if ('href' in x) { <a [href]="x.href" target="_blank" rel="noopener">Open its spans and logs ↗</a> }
184
+ @else { <a [routerLink]="x.route">Open its spans and logs ↗</a> }</p>
185
+ }
186
+ @if (trace.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
187
+ @if (trace.error()) { <p class="ja-error">{{ error() }}</p> }
188
+ @if (trace.value(); as t) {
189
+ @if (t.accessLogs.length === 0 && t.dataChanges.length === 0) {
190
+ <p class="ja-muted">Nothing was audited under this trace id.</p>
191
+ }
192
+ @if (t.truncated) { <p class="ja-notice">This trace has more records than the {{ t.accessLogs.length }} access records and {{ t.dataChanges.length }} changes shown.</p> }
193
+ @if (t.accessLogs.length) {
194
+ <section class="ja-card">
195
+ <h2>Access records ({{ t.accessLogs.length }})</h2>
196
+ <ja-access-log-table [rows]="accessLogs()" />
197
+ </section>
198
+ }
199
+ @if (t.dataChanges.length) {
200
+ <h2>Data changes ({{ t.dataChanges.length }})</h2>
201
+ @for (c of t.dataChanges; track c.id) {
202
+ <section class="ja-card">
203
+ <div class="ja-row">
204
+ <span class="ja-summary">
205
+ <ja-action [action]="c.action" />
206
+ <a class="ja-mono" [routerLink]="['data-changes', c.id] | jaLink" [queryParams]="ctx.keep()">{{ c.schema ? c.schema + '.' : '' }}{{ c.table }}</a>
207
+ <span class="ja-mono ja-small">{{ c.keys | jaKeys }}</span>
208
+ </span>
209
+ <span class="ja-muted ja-small">{{ c.dateTime | date: 'HH:mm:ss.SSS' }} · {{ c.user || 'no user' }}</span>
210
+ </div>
211
+ <ja-change-diff [changes]="c.changes" />
212
+ </section>
213
+ }
214
+ }
215
+ }`
216
+ }]
217
+ }],
218
+ propDecorators: { traceId: [{
219
+ type: i0.Input,
220
+ args: [{
221
+ isSignal: true,
222
+ alias: "traceId",
223
+ required: true
224
+ }]
225
+ }] }
226
+ });
227
+ export { TracePage };
228
+
229
+ //# sourceMappingURL=juice-js-audit-trace.page-Df6Sy2x8.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juice-js-audit-trace.page-Df6Sy2x8.mjs","names":[],"sources":["../../../../projects/juice-js/audit/src/lib/pages/trace.page.ts"],"sourcesContent":["import { DatePipe } from '@angular/common';\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 { AuditApiService } from '../core/api.service';\nimport { accessLogSummary } from '../core/models';\nimport { AuditContextService } from '../core/context.service';\nimport { AuditLinkPipe, AuditLinks } from '../core/options';\nimport { KeysPipe, problemText } from '../shared/format';\nimport { AccessLogTable, ActionBadge, AuditContextBar, ChangeDiff } from '../shared/ui';\n\n/**\n * Everything audited under one trace id, across services: the requests, messages and jobs that ran, and every row they\n * changed with its values, in order.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [RouterLink, DatePipe, MatProgressBarModule, AuditLinkPipe, KeysPipe, AuditContextBar, AccessLogTable,\n ActionBadge, ChangeDiff],\n template: `\n <ja-context-bar [showRange]=\"false\"><h1>Trace <span class=\"ja-mono ja-h-id\">{{ traceId() }}</span></h1></ja-context-bar>\n @if (external(); as x) {\n <p>@if ('href' in x) { <a [href]=\"x.href\" target=\"_blank\" rel=\"noopener\">Open its spans and logs ↗</a> }\n @else { <a [routerLink]=\"x.route\">Open its spans and logs ↗</a> }</p>\n }\n @if (trace.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (trace.error()) { <p class=\"ja-error\">{{ error() }}</p> }\n @if (trace.value(); as t) {\n @if (t.accessLogs.length === 0 && t.dataChanges.length === 0) {\n <p class=\"ja-muted\">Nothing was audited under this trace id.</p>\n }\n @if (t.truncated) { <p class=\"ja-notice\">This trace has more records than the {{ t.accessLogs.length }} access records and {{ t.dataChanges.length }} changes shown.</p> }\n @if (t.accessLogs.length) {\n <section class=\"ja-card\">\n <h2>Access records ({{ t.accessLogs.length }})</h2>\n <ja-access-log-table [rows]=\"accessLogs()\" />\n </section>\n }\n @if (t.dataChanges.length) {\n <h2>Data changes ({{ t.dataChanges.length }})</h2>\n @for (c of t.dataChanges; track c.id) {\n <section class=\"ja-card\">\n <div class=\"ja-row\">\n <span class=\"ja-summary\">\n <ja-action [action]=\"c.action\" />\n <a class=\"ja-mono\" [routerLink]=\"['data-changes', c.id] | jaLink\" [queryParams]=\"ctx.keep()\">{{ c.schema ? c.schema + '.' : '' }}{{ c.table }}</a>\n <span class=\"ja-mono ja-small\">{{ c.keys | jaKeys }}</span>\n </span>\n <span class=\"ja-muted ja-small\">{{ c.dateTime | date: 'HH:mm:ss.SSS' }} · {{ c.user || 'no user' }}</span>\n </div>\n <ja-change-diff [changes]=\"c.changes\" />\n </section>\n }\n }\n }`,\n})\nexport class TracePage {\n private readonly api = inject(AuditApiService);\n private readonly links = inject(AuditLinks);\n protected readonly ctx = inject(AuditContextService);\n readonly traceId = input.required<string>();\n\n protected readonly trace = apiResource({ params: () => this.traceId(), stream: ({ params }) => this.api.trace(params) });\n protected readonly external = computed(() => this.links.externalTrace(this.trace.value()?.traceId ?? this.traceId()));\n protected readonly accessLogs = computed(() => (this.trace.value()?.accessLogs ?? []).map(accessLogSummary));\n protected readonly error = computed(() => problemText(this.trace.error()));\n}\n"],"mappings":";;;;;;;;AAyDA,IAAa,YAAb,MAAa,UAAS;CACH,MAAM,OAAO,eAAe;CAC5B,QAAQ,OAAO,UAAU;CACvB,MAAM,OAAO,mBAAmB;CAC1C,UAAU,MAAM,SAAkB,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAExB,QAAQ,YAAY;EAAE,cAAc,KAAK,QAAO;EAAI,SAAS,EAAE,aAAa,KAAK,IAAI,MAAM,MAAM;CAAC,CAAE;CACpG,WAAW,eAAe,KAAK,MAAM,cAAc,KAAK,MAAM,MAAK,CAAE,EAAE,WAAW,KAAK,QAAO,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAClG,aAAa,gBAAgB,KAAK,MAAM,MAAK,CAAE,EAAE,cAAc,CAAA,EAAA,CAAI,IAAI,gBAAgB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CACzF,QAAQ,eAAe,YAAY,KAAK,MAAM,MAAK,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAT/D,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,QAAA,EAAA,SAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,UAAA;EAAA,UArCV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmCN,UAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MArCM;IAAU,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAY;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,MAA2B;IAAe,UAAA;IAAA,QAAA,CAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAc,UAAA;IAAA,QAAA,CAAA,QAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAC5G;IAAW,UAAA;IAAA,QAAA,CAAA,QAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAU,UAAA;IAAA,QAAA,CAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MADH;IAAQ,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAwB;IAAa,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAQ,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAuClE,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAS,YAAA,CAAA;EAzCrB,MAAA;EAAU,MAAA,CAAA;GACT,iBAAiB,wBAAwB;GACzC,SAAS;IAAC;IAAY;IAAU;IAAsB;IAAe;IAAU;IAAiB;IAC9F;IAAa;GAAU;GACzB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCX,CAAA"}