@juice-js/audit 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.
@@ -0,0 +1,588 @@
1
+ import { AuditApiService, AuditContextService } from "./juice-js-audit.mjs";
2
+ import { p as problemText, r as AuditContextBar, t as AccessLogTable } from "./juice-js-audit-ui-DnfhiB6p.mjs";
3
+ import { t as cursorList } from "./juice-js-audit-paging-D5-1J1rG.mjs";
4
+ import * as i0 from "@angular/core";
5
+ import { ChangeDetectionStrategy, Component, computed, inject, input, linkedSignal } from "@angular/core";
6
+ import * as i6 from "@angular/material/progress-bar";
7
+ import { MatProgressBarModule } from "@angular/material/progress-bar";
8
+ import * as i1 from "@angular/forms";
9
+ import { FormsModule } from "@angular/forms";
10
+ import * as i5 from "@angular/material/select";
11
+ import { MatSelectModule } from "@angular/material/select";
12
+ import * as i2 from "@angular/material/button";
13
+ import { MatButtonModule } from "@angular/material/button";
14
+ import * as i3 from "@angular/material/checkbox";
15
+ import { MatCheckboxModule } from "@angular/material/checkbox";
16
+ import * as i4 from "@angular/material/input";
17
+ import { MatInputModule } from "@angular/material/input";
18
+ var AccessLogsPage = class AccessLogsPage {
19
+ api = inject(AuditApiService);
20
+ ctx = inject(AuditContextService);
21
+ user = input(...ngDevMode ? [void 0, { debugName: "user" }] : /* istanbul ignore next */ []);
22
+ action = input(...ngDevMode ? [void 0, { debugName: "action" }] : /* istanbul ignore next */ []);
23
+ path = input(...ngDevMode ? [void 0, { debugName: "path" }] : /* istanbul ignore next */ []);
24
+ method = input(...ngDevMode ? [void 0, { debugName: "method" }] : /* istanbul ignore next */ []);
25
+ status = input(...ngDevMode ? [void 0, { debugName: "status" }] : /* istanbul ignore next */ []);
26
+ app = input(...ngDevMode ? [void 0, { debugName: "app" }] : /* istanbul ignore next */ []);
27
+ minMs = input(...ngDevMode ? [void 0, { debugName: "minMs" }] : /* istanbul ignore next */ []);
28
+ restricted = input(...ngDevMode ? [void 0, { debugName: "restricted" }] : /* istanbul ignore next */ []);
29
+ traceId = input(...ngDevMode ? [void 0, { debugName: "traceId" }] : /* istanbul ignore next */ []);
30
+ methods = [
31
+ "GET",
32
+ "POST",
33
+ "PUT",
34
+ "PATCH",
35
+ "DELETE",
36
+ "MESSAGE",
37
+ "REQUEST",
38
+ "NOTIFICATION"
39
+ ];
40
+ statuses = [
41
+ "2xx",
42
+ "3xx",
43
+ "4xx",
44
+ "5xx"
45
+ ];
46
+ filters = computed(() => ({
47
+ user: this.user() ?? "",
48
+ action: this.action() ?? "",
49
+ path: this.path() ?? "",
50
+ method: this.method() ?? "",
51
+ status: this.status() ?? "",
52
+ app: this.app() ?? "",
53
+ minMs: this.minMs() ?? "",
54
+ restricted: this.restricted() === "true",
55
+ traceId: this.traceId() ?? ""
56
+ }), ...ngDevMode ? [{ debugName: "filters" }] : /* istanbul ignore next */ []);
57
+ form = linkedSignal(() => ({ ...this.filters() }), ...ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []);
58
+ filtered = computed(() => Object.values(this.filters()).some((v) => v !== "" && v !== false), ...ngDevMode ? [{ debugName: "filtered" }] : /* istanbul ignore next */ []);
59
+ logs = cursorList(() => ({
60
+ filters: this.filters(),
61
+ range: this.ctx.range(),
62
+ abs: this.ctx.absolute()
63
+ }), (p) => ({
64
+ ...this.ctx.window(),
65
+ ...p.filters,
66
+ restricted: p.filters.restricted ? true : null,
67
+ limit: 50
68
+ }), (q) => this.api.accessLogs(q));
69
+ error = computed(() => problemText(this.logs.first.error()), ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
70
+ moreError = computed(() => problemText(this.logs.moreError()), ...ngDevMode ? [{ debugName: "moreError" }] : /* istanbul ignore next */ []);
71
+ apply() {
72
+ const f = this.form();
73
+ this.ctx.filter({
74
+ user: f.user.trim() || null,
75
+ action: f.action.trim() || null,
76
+ path: f.path.trim() || null,
77
+ method: f.method || null,
78
+ status: f.status || null,
79
+ app: f.app.trim() || null,
80
+ minMs: String(f.minMs ?? "").trim() || null,
81
+ restricted: f.restricted ? "true" : null,
82
+ traceId: f.traceId.trim() || null
83
+ });
84
+ }
85
+ clear() {
86
+ this.ctx.filter({
87
+ user: null,
88
+ action: null,
89
+ path: null,
90
+ method: null,
91
+ status: null,
92
+ app: null,
93
+ minMs: null,
94
+ restricted: null,
95
+ traceId: null
96
+ });
97
+ }
98
+ static ɵfac = i0.ɵɵngDeclareFactory({
99
+ minVersion: "12.0.0",
100
+ version: "22.2.4",
101
+ ngImport: i0,
102
+ type: AccessLogsPage,
103
+ deps: [],
104
+ target: i0.ɵɵFactoryTarget.Component
105
+ });
106
+ static ɵcmp = i0.ɵɵngDeclareComponent({
107
+ minVersion: "17.0.0",
108
+ version: "22.2.4",
109
+ type: AccessLogsPage,
110
+ isStandalone: true,
111
+ selector: "ng-component",
112
+ inputs: {
113
+ user: {
114
+ classPropertyName: "user",
115
+ publicName: "user",
116
+ isSignal: true,
117
+ isRequired: false,
118
+ transformFunction: null
119
+ },
120
+ action: {
121
+ classPropertyName: "action",
122
+ publicName: "action",
123
+ isSignal: true,
124
+ isRequired: false,
125
+ transformFunction: null
126
+ },
127
+ path: {
128
+ classPropertyName: "path",
129
+ publicName: "path",
130
+ isSignal: true,
131
+ isRequired: false,
132
+ transformFunction: null
133
+ },
134
+ method: {
135
+ classPropertyName: "method",
136
+ publicName: "method",
137
+ isSignal: true,
138
+ isRequired: false,
139
+ transformFunction: null
140
+ },
141
+ status: {
142
+ classPropertyName: "status",
143
+ publicName: "status",
144
+ isSignal: true,
145
+ isRequired: false,
146
+ transformFunction: null
147
+ },
148
+ app: {
149
+ classPropertyName: "app",
150
+ publicName: "app",
151
+ isSignal: true,
152
+ isRequired: false,
153
+ transformFunction: null
154
+ },
155
+ minMs: {
156
+ classPropertyName: "minMs",
157
+ publicName: "minMs",
158
+ isSignal: true,
159
+ isRequired: false,
160
+ transformFunction: null
161
+ },
162
+ restricted: {
163
+ classPropertyName: "restricted",
164
+ publicName: "restricted",
165
+ isSignal: true,
166
+ isRequired: false,
167
+ transformFunction: null
168
+ },
169
+ traceId: {
170
+ classPropertyName: "traceId",
171
+ publicName: "traceId",
172
+ isSignal: true,
173
+ isRequired: false,
174
+ transformFunction: null
175
+ }
176
+ },
177
+ ngImport: i0,
178
+ template: `
179
+ <ja-context-bar><h1>Access records</h1></ja-context-bar>
180
+ <form class="ja-filter-form" (ngSubmit)="apply()">
181
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-sm"><mat-label>User</mat-label><input matInput name="user" [(ngModel)]="form().user"></mat-form-field>
182
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-sm"><mat-label>Action</mat-label><input matInput name="action" [(ngModel)]="form().action"></mat-form-field>
183
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-sm"><mat-label>Path</mat-label><input matInput name="path" [(ngModel)]="form().path"></mat-form-field>
184
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-xs">
185
+ <mat-label>Method</mat-label>
186
+ <mat-select name="method" [(ngModel)]="form().method">
187
+ <mat-option value="">Any</mat-option>
188
+ @for (m of methods; track m) { <mat-option [value]="m">{{ m }}</mat-option> }
189
+ </mat-select>
190
+ </mat-form-field>
191
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-xs">
192
+ <mat-label>Status</mat-label>
193
+ <mat-select name="status" [(ngModel)]="form().status">
194
+ <mat-option value="">Any</mat-option>
195
+ <mat-option value="error">Failed (4xx, 5xx)</mat-option>
196
+ @for (s of statuses; track s) { <mat-option [value]="s">{{ s }}</mat-option> }
197
+ </mat-select>
198
+ </mat-form-field>
199
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-sm"><mat-label>App</mat-label><input matInput name="app" [(ngModel)]="form().app"></mat-form-field>
200
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-xs"><mat-label>Slower than (ms)</mat-label><input matInput type="number" min="0" name="minMs" [(ngModel)]="form().minMs"></mat-form-field>
201
+ <mat-checkbox name="restricted" [(ngModel)]="form().restricted">Restricted only</mat-checkbox>
202
+ <button mat-flat-button type="submit">Search</button>
203
+ @if (filtered()) { <button mat-button type="button" (click)="clear()">Clear</button> }
204
+ </form>
205
+
206
+ @if (logs.first.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
207
+ @if (logs.first.error()) { <p class="ja-error">{{ error() }}</p> }
208
+ @if (logs.first.hasValue()) {
209
+ @if (logs.items().length === 0) { <p class="ja-muted">No access records match in this window.</p> }
210
+ @else {
211
+ <ja-access-log-table [rows]="logs.items()" />
212
+ <div class="ja-more">
213
+ <span class="ja-muted">{{ logs.items().length }} record{{ logs.items().length === 1 ? '' : 's' }}{{ logs.hasMore() ? ', newest first' : '' }}</span>
214
+ @if (logs.hasMore()) {
215
+ <button mat-button (click)="logs.more()" [disabled]="logs.loadingMore()">{{ logs.loadingMore() ? 'Loading…' : 'Older records' }}</button>
216
+ }
217
+ @if (logs.moreError()) { <span class="ja-error">{{ moreError() }}</span> }
218
+ </div>
219
+ }
220
+ }`,
221
+ isInline: true,
222
+ dependencies: [
223
+ {
224
+ kind: "ngmodule",
225
+ type: FormsModule
226
+ },
227
+ {
228
+ kind: "directive",
229
+ type: i1.ɵNgNoValidate,
230
+ selector: "form:not([ngNoForm]):not([ngNativeValidate])"
231
+ },
232
+ {
233
+ kind: "directive",
234
+ type: i1.DefaultValueAccessor,
235
+ selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]"
236
+ },
237
+ {
238
+ kind: "directive",
239
+ type: i1.NumberValueAccessor,
240
+ selector: "input[type=number]:not([ngNoCva])[formControlName],input[type=number]:not([ngNoCva])[formControl],input[type=number]:not([ngNoCva])[ngModel]"
241
+ },
242
+ {
243
+ kind: "directive",
244
+ type: i1.NgControlStatus,
245
+ selector: "[formControlName],[ngModel],[formControl]"
246
+ },
247
+ {
248
+ kind: "directive",
249
+ type: i1.NgControlStatusGroup,
250
+ selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]"
251
+ },
252
+ {
253
+ kind: "directive",
254
+ type: i1.MinValidator,
255
+ selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",
256
+ inputs: ["min"]
257
+ },
258
+ {
259
+ kind: "directive",
260
+ type: i1.NgModel,
261
+ selector: "[ngModel]:not([formControlName]):not([formControl])",
262
+ inputs: [
263
+ "name",
264
+ "disabled",
265
+ "ngModel",
266
+ "ngModelOptions"
267
+ ],
268
+ outputs: ["ngModelChange"],
269
+ exportAs: ["ngModel"]
270
+ },
271
+ {
272
+ kind: "directive",
273
+ type: i1.NgForm,
274
+ selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]",
275
+ inputs: ["ngFormOptions"],
276
+ outputs: ["ngSubmit"],
277
+ exportAs: ["ngForm"]
278
+ },
279
+ {
280
+ kind: "ngmodule",
281
+ type: MatButtonModule
282
+ },
283
+ {
284
+ kind: "component",
285
+ type: i2.MatButton,
286
+ selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ",
287
+ inputs: ["matButton"],
288
+ exportAs: ["matButton", "matAnchor"]
289
+ },
290
+ {
291
+ kind: "ngmodule",
292
+ type: MatCheckboxModule
293
+ },
294
+ {
295
+ kind: "component",
296
+ type: i3.MatCheckbox,
297
+ selector: "mat-checkbox",
298
+ inputs: [
299
+ "aria-label",
300
+ "aria-labelledby",
301
+ "aria-describedby",
302
+ "aria-expanded",
303
+ "aria-controls",
304
+ "aria-owns",
305
+ "id",
306
+ "required",
307
+ "labelPosition",
308
+ "name",
309
+ "value",
310
+ "disableRipple",
311
+ "tabIndex",
312
+ "color",
313
+ "disabledInteractive",
314
+ "checked",
315
+ "disabled",
316
+ "indeterminate"
317
+ ],
318
+ outputs: ["change", "indeterminateChange"],
319
+ exportAs: ["matCheckbox"]
320
+ },
321
+ {
322
+ kind: "ngmodule",
323
+ type: MatInputModule
324
+ },
325
+ {
326
+ kind: "directive",
327
+ type: i4.MatInput,
328
+ selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",
329
+ inputs: [
330
+ "disabled",
331
+ "id",
332
+ "placeholder",
333
+ "name",
334
+ "required",
335
+ "type",
336
+ "errorStateMatcher",
337
+ "aria-describedby",
338
+ "value",
339
+ "readonly",
340
+ "disabledInteractive"
341
+ ],
342
+ exportAs: ["matInput"]
343
+ },
344
+ {
345
+ kind: "component",
346
+ type: i5.MatFormField,
347
+ selector: "mat-form-field",
348
+ inputs: [
349
+ "hideRequiredMarker",
350
+ "color",
351
+ "floatLabel",
352
+ "appearance",
353
+ "subscriptSizing",
354
+ "hintLabel"
355
+ ],
356
+ exportAs: ["matFormField"]
357
+ },
358
+ {
359
+ kind: "directive",
360
+ type: i5.MatLabel,
361
+ selector: "mat-label"
362
+ },
363
+ {
364
+ kind: "ngmodule",
365
+ type: MatProgressBarModule
366
+ },
367
+ {
368
+ kind: "component",
369
+ type: i6.MatProgressBar,
370
+ selector: "mat-progress-bar",
371
+ inputs: [
372
+ "color",
373
+ "value",
374
+ "bufferValue",
375
+ "mode"
376
+ ],
377
+ outputs: ["animationEnd"],
378
+ exportAs: ["matProgressBar"]
379
+ },
380
+ {
381
+ kind: "ngmodule",
382
+ type: MatSelectModule
383
+ },
384
+ {
385
+ kind: "component",
386
+ type: i5.MatSelect,
387
+ selector: "mat-select",
388
+ inputs: [
389
+ "aria-describedby",
390
+ "panelClass",
391
+ "disabled",
392
+ "disableRipple",
393
+ "tabIndex",
394
+ "hideSingleSelectionIndicator",
395
+ "placeholder",
396
+ "required",
397
+ "multiple",
398
+ "disableOptionCentering",
399
+ "compareWith",
400
+ "value",
401
+ "aria-label",
402
+ "aria-labelledby",
403
+ "errorStateMatcher",
404
+ "typeaheadDebounceInterval",
405
+ "sortComparator",
406
+ "id",
407
+ "panelWidth",
408
+ "canSelectNullableOptions"
409
+ ],
410
+ outputs: [
411
+ "openedChange",
412
+ "opened",
413
+ "closed",
414
+ "selectionChange",
415
+ "valueChange"
416
+ ],
417
+ exportAs: ["matSelect"]
418
+ },
419
+ {
420
+ kind: "component",
421
+ type: i5.MatOption,
422
+ selector: "mat-option",
423
+ inputs: [
424
+ "value",
425
+ "id",
426
+ "disabled"
427
+ ],
428
+ outputs: ["onSelectionChange"],
429
+ exportAs: ["matOption"]
430
+ },
431
+ {
432
+ kind: "component",
433
+ type: AuditContextBar,
434
+ selector: "ja-context-bar",
435
+ inputs: ["showRange"]
436
+ },
437
+ {
438
+ kind: "component",
439
+ type: AccessLogTable,
440
+ selector: "ja-access-log-table",
441
+ inputs: ["rows", "compact"]
442
+ }
443
+ ],
444
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
445
+ });
446
+ };
447
+ i0.ɵɵngDeclareClassMetadata({
448
+ minVersion: "12.0.0",
449
+ version: "22.2.4",
450
+ ngImport: i0,
451
+ type: AccessLogsPage,
452
+ decorators: [{
453
+ type: Component,
454
+ args: [{
455
+ changeDetection: ChangeDetectionStrategy.OnPush,
456
+ imports: [
457
+ FormsModule,
458
+ MatButtonModule,
459
+ MatCheckboxModule,
460
+ MatInputModule,
461
+ MatProgressBarModule,
462
+ MatSelectModule,
463
+ AuditContextBar,
464
+ AccessLogTable
465
+ ],
466
+ template: `
467
+ <ja-context-bar><h1>Access records</h1></ja-context-bar>
468
+ <form class="ja-filter-form" (ngSubmit)="apply()">
469
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-sm"><mat-label>User</mat-label><input matInput name="user" [(ngModel)]="form().user"></mat-form-field>
470
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-sm"><mat-label>Action</mat-label><input matInput name="action" [(ngModel)]="form().action"></mat-form-field>
471
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-sm"><mat-label>Path</mat-label><input matInput name="path" [(ngModel)]="form().path"></mat-form-field>
472
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-xs">
473
+ <mat-label>Method</mat-label>
474
+ <mat-select name="method" [(ngModel)]="form().method">
475
+ <mat-option value="">Any</mat-option>
476
+ @for (m of methods; track m) { <mat-option [value]="m">{{ m }}</mat-option> }
477
+ </mat-select>
478
+ </mat-form-field>
479
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-xs">
480
+ <mat-label>Status</mat-label>
481
+ <mat-select name="status" [(ngModel)]="form().status">
482
+ <mat-option value="">Any</mat-option>
483
+ <mat-option value="error">Failed (4xx, 5xx)</mat-option>
484
+ @for (s of statuses; track s) { <mat-option [value]="s">{{ s }}</mat-option> }
485
+ </mat-select>
486
+ </mat-form-field>
487
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-sm"><mat-label>App</mat-label><input matInput name="app" [(ngModel)]="form().app"></mat-form-field>
488
+ <mat-form-field subscriptSizing="dynamic" class="ja-field-xs"><mat-label>Slower than (ms)</mat-label><input matInput type="number" min="0" name="minMs" [(ngModel)]="form().minMs"></mat-form-field>
489
+ <mat-checkbox name="restricted" [(ngModel)]="form().restricted">Restricted only</mat-checkbox>
490
+ <button mat-flat-button type="submit">Search</button>
491
+ @if (filtered()) { <button mat-button type="button" (click)="clear()">Clear</button> }
492
+ </form>
493
+
494
+ @if (logs.first.isLoading()) { <mat-progress-bar mode="indeterminate" /> }
495
+ @if (logs.first.error()) { <p class="ja-error">{{ error() }}</p> }
496
+ @if (logs.first.hasValue()) {
497
+ @if (logs.items().length === 0) { <p class="ja-muted">No access records match in this window.</p> }
498
+ @else {
499
+ <ja-access-log-table [rows]="logs.items()" />
500
+ <div class="ja-more">
501
+ <span class="ja-muted">{{ logs.items().length }} record{{ logs.items().length === 1 ? '' : 's' }}{{ logs.hasMore() ? ', newest first' : '' }}</span>
502
+ @if (logs.hasMore()) {
503
+ <button mat-button (click)="logs.more()" [disabled]="logs.loadingMore()">{{ logs.loadingMore() ? 'Loading…' : 'Older records' }}</button>
504
+ }
505
+ @if (logs.moreError()) { <span class="ja-error">{{ moreError() }}</span> }
506
+ </div>
507
+ }
508
+ }`
509
+ }]
510
+ }],
511
+ propDecorators: {
512
+ user: [{
513
+ type: i0.Input,
514
+ args: [{
515
+ isSignal: true,
516
+ alias: "user",
517
+ required: false
518
+ }]
519
+ }],
520
+ action: [{
521
+ type: i0.Input,
522
+ args: [{
523
+ isSignal: true,
524
+ alias: "action",
525
+ required: false
526
+ }]
527
+ }],
528
+ path: [{
529
+ type: i0.Input,
530
+ args: [{
531
+ isSignal: true,
532
+ alias: "path",
533
+ required: false
534
+ }]
535
+ }],
536
+ method: [{
537
+ type: i0.Input,
538
+ args: [{
539
+ isSignal: true,
540
+ alias: "method",
541
+ required: false
542
+ }]
543
+ }],
544
+ status: [{
545
+ type: i0.Input,
546
+ args: [{
547
+ isSignal: true,
548
+ alias: "status",
549
+ required: false
550
+ }]
551
+ }],
552
+ app: [{
553
+ type: i0.Input,
554
+ args: [{
555
+ isSignal: true,
556
+ alias: "app",
557
+ required: false
558
+ }]
559
+ }],
560
+ minMs: [{
561
+ type: i0.Input,
562
+ args: [{
563
+ isSignal: true,
564
+ alias: "minMs",
565
+ required: false
566
+ }]
567
+ }],
568
+ restricted: [{
569
+ type: i0.Input,
570
+ args: [{
571
+ isSignal: true,
572
+ alias: "restricted",
573
+ required: false
574
+ }]
575
+ }],
576
+ traceId: [{
577
+ type: i0.Input,
578
+ args: [{
579
+ isSignal: true,
580
+ alias: "traceId",
581
+ required: false
582
+ }]
583
+ }]
584
+ }
585
+ });
586
+ export { AccessLogsPage };
587
+
588
+ //# sourceMappingURL=juice-js-audit-access-logs.page-qVBQLq2K.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"juice-js-audit-access-logs.page-qVBQLq2K.mjs","names":[],"sources":["../../../../projects/juice-js/audit/src/lib/pages/access-logs.page.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject, input, linkedSignal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { MatInputModule } from '@angular/material/input';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { MatSelectModule } from '@angular/material/select';\nimport { AuditApiService } from '../core/api.service';\nimport { AuditContextService } from '../core/context.service';\nimport { problemText } from '../shared/format';\nimport { cursorList } from '../shared/paging';\nimport { AccessLogTable, AuditContextBar } from '../shared/ui';\n\n/**\n * The access records in the window, newest first: who did what, with what outcome and how long it took. The filters\n * are in the URL, so a filtered list is a link to share.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [FormsModule, MatButtonModule, MatCheckboxModule, MatInputModule, MatProgressBarModule, MatSelectModule,\n AuditContextBar, AccessLogTable],\n template: `\n <ja-context-bar><h1>Access records</h1></ja-context-bar>\n <form class=\"ja-filter-form\" (ngSubmit)=\"apply()\">\n <mat-form-field subscriptSizing=\"dynamic\" class=\"ja-field-sm\"><mat-label>User</mat-label><input matInput name=\"user\" [(ngModel)]=\"form().user\"></mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"ja-field-sm\"><mat-label>Action</mat-label><input matInput name=\"action\" [(ngModel)]=\"form().action\"></mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"ja-field-sm\"><mat-label>Path</mat-label><input matInput name=\"path\" [(ngModel)]=\"form().path\"></mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"ja-field-xs\">\n <mat-label>Method</mat-label>\n <mat-select name=\"method\" [(ngModel)]=\"form().method\">\n <mat-option value=\"\">Any</mat-option>\n @for (m of methods; track m) { <mat-option [value]=\"m\">{{ m }}</mat-option> }\n </mat-select>\n </mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"ja-field-xs\">\n <mat-label>Status</mat-label>\n <mat-select name=\"status\" [(ngModel)]=\"form().status\">\n <mat-option value=\"\">Any</mat-option>\n <mat-option value=\"error\">Failed (4xx, 5xx)</mat-option>\n @for (s of statuses; track s) { <mat-option [value]=\"s\">{{ s }}</mat-option> }\n </mat-select>\n </mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"ja-field-sm\"><mat-label>App</mat-label><input matInput name=\"app\" [(ngModel)]=\"form().app\"></mat-form-field>\n <mat-form-field subscriptSizing=\"dynamic\" class=\"ja-field-xs\"><mat-label>Slower than (ms)</mat-label><input matInput type=\"number\" min=\"0\" name=\"minMs\" [(ngModel)]=\"form().minMs\"></mat-form-field>\n <mat-checkbox name=\"restricted\" [(ngModel)]=\"form().restricted\">Restricted only</mat-checkbox>\n <button mat-flat-button type=\"submit\">Search</button>\n @if (filtered()) { <button mat-button type=\"button\" (click)=\"clear()\">Clear</button> }\n </form>\n\n @if (logs.first.isLoading()) { <mat-progress-bar mode=\"indeterminate\" /> }\n @if (logs.first.error()) { <p class=\"ja-error\">{{ error() }}</p> }\n @if (logs.first.hasValue()) {\n @if (logs.items().length === 0) { <p class=\"ja-muted\">No access records match in this window.</p> }\n @else {\n <ja-access-log-table [rows]=\"logs.items()\" />\n <div class=\"ja-more\">\n <span class=\"ja-muted\">{{ logs.items().length }} record{{ logs.items().length === 1 ? '' : 's' }}{{ logs.hasMore() ? ', newest first' : '' }}</span>\n @if (logs.hasMore()) {\n <button mat-button (click)=\"logs.more()\" [disabled]=\"logs.loadingMore()\">{{ logs.loadingMore() ? 'Loading…' : 'Older records' }}</button>\n }\n @if (logs.moreError()) { <span class=\"ja-error\">{{ moreError() }}</span> }\n </div>\n }\n }`,\n})\nexport class AccessLogsPage {\n private readonly api = inject(AuditApiService);\n protected readonly ctx = inject(AuditContextService);\n\n readonly user = input<string>();\n readonly action = input<string>();\n readonly path = input<string>();\n readonly method = input<string>();\n readonly status = input<string>();\n readonly app = input<string>();\n readonly minMs = input<string>();\n readonly restricted = input<string>();\n readonly traceId = input<string>();\n\n protected readonly methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'MESSAGE', 'REQUEST', 'NOTIFICATION'];\n protected readonly statuses = ['2xx', '3xx', '4xx', '5xx'];\n\n private readonly filters = computed(() => ({\n user: this.user() ?? '', action: this.action() ?? '', path: this.path() ?? '', method: this.method() ?? '',\n status: this.status() ?? '', app: this.app() ?? '', minMs: this.minMs() ?? '', restricted: this.restricted() === 'true',\n traceId: this.traceId() ?? '',\n }));\n /** The form, reset to the URL's filters whenever they change. */\n protected readonly form = linkedSignal(() => ({ ...this.filters() }));\n protected readonly filtered = computed(() => Object.values(this.filters()).some(v => v !== '' && v !== false));\n\n protected readonly logs = cursorList(\n () => ({ filters: this.filters(), range: this.ctx.range(), abs: this.ctx.absolute() }),\n p => ({ ...this.ctx.window(), ...p.filters, restricted: p.filters.restricted ? true : null, limit: 50 }),\n q => this.api.accessLogs(q));\n protected readonly error = computed(() => problemText(this.logs.first.error()));\n protected readonly moreError = computed(() => problemText(this.logs.moreError()));\n\n apply() {\n const f = this.form();\n this.ctx.filter({\n user: f.user.trim() || null, action: f.action.trim() || null, path: f.path.trim() || null, method: f.method || null,\n status: f.status || null, app: f.app.trim() || null, minMs: String(f.minMs ?? '').trim() || null,\n restricted: f.restricted ? 'true' : null, traceId: f.traceId.trim() || null,\n });\n }\n\n clear() {\n this.ctx.filter({ user: null, action: null, path: null, method: null, status: null, app: null, minMs: null, restricted: null, traceId: null });\n }\n}\n"],"mappings":"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"}