hazo_audit 1.0.0 → 2.0.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.
- package/CHANGE_LOG.md +72 -0
- package/README.md +138 -1
- package/SETUP_CHECKLIST.md +9 -0
- package/config/hazo_audit_config.ini.sample +14 -4
- package/dist/client/AuditViewer.d.ts +13 -0
- package/dist/client/AuditViewer.d.ts.map +1 -0
- package/dist/client/AuditViewer.js +52 -0
- package/dist/client/AuditViewer.js.map +1 -0
- package/dist/client/FieldAuditIcon.d.ts.map +1 -1
- package/dist/client/FieldAuditIcon.js +2 -2
- package/dist/client/FieldAuditIcon.js.map +1 -1
- package/dist/client/FieldAuditTrail.d.ts.map +1 -1
- package/dist/client/FieldAuditTrail.js +71 -8
- package/dist/client/FieldAuditTrail.js.map +1 -1
- package/dist/client/RevertConfirmDialog.d.ts +11 -0
- package/dist/client/RevertConfirmDialog.d.ts.map +1 -0
- package/dist/client/RevertConfirmDialog.js +31 -0
- package/dist/client/RevertConfirmDialog.js.map +1 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/index.d.ts +73 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +5 -0
- package/dist/nextjs/index.d.ts.map +1 -1
- package/dist/nextjs/index.js +78 -1
- package/dist/nextjs/index.js.map +1 -1
- package/dist/server/diff.js +11 -3
- package/dist/server/diff.js.map +1 -1
- package/dist/server/errors.d.ts +6 -0
- package/dist/server/errors.d.ts.map +1 -0
- package/dist/server/errors.js +9 -0
- package/dist/server/errors.js.map +1 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +8 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/intent.d.ts +9 -0
- package/dist/server/intent.d.ts.map +1 -0
- package/dist/server/intent.js +102 -0
- package/dist/server/intent.js.map +1 -0
- package/dist/server/query.d.ts +22 -0
- package/dist/server/query.d.ts.map +1 -0
- package/dist/server/query.js +52 -0
- package/dist/server/query.js.map +1 -0
- package/dist/server/revert.d.ts +20 -0
- package/dist/server/revert.d.ts.map +1 -0
- package/dist/server/revert.js +89 -0
- package/dist/server/revert.js.map +1 -0
- package/dist/server/snapshot.d.ts +38 -0
- package/dist/server/snapshot.d.ts.map +1 -0
- package/dist/server/snapshot.js +68 -0
- package/dist/server/snapshot.js.map +1 -0
- package/dist/server/worker.d.ts.map +1 -1
- package/dist/server/worker.js +8 -0
- package/dist/server/worker.js.map +1 -1
- package/package.json +8 -3
package/CHANGE_LOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# Change log
|
|
2
2
|
|
|
3
|
+
## 2.0.2 — 2026-05-27
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`opLabels` prop** on `<FieldAuditTrail />` and `<FieldAuditIcon />` for
|
|
8
|
+
overriding the op badge text per app. Shape: `{ insert?, update?, delete? }`.
|
|
9
|
+
Exported alongside `DEFAULT_OP_LABELS` for apps that want to compose on top
|
|
10
|
+
of the defaults. Empty-string override falls back to the raw DB op so apps
|
|
11
|
+
can opt back into the legacy uppercase rendering per-op.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **Op badge defaults** — `INSERT` / `UPDATE` / `DELETE` are now rendered as
|
|
16
|
+
`Added` / `Changed` / `Removed` (action-oriented, past tense). This reads
|
|
17
|
+
naturally next to the actor line: `Added · Pubs Abayasiri`. The uppercase
|
|
18
|
+
text-transform on the badge was dropped so casing in `opLabels` is honoured.
|
|
19
|
+
|
|
20
|
+
## 2.0.1 — 2026-05-20
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **`revert()` API cleanup** — removed redundant `app_adapter` field from `RevertArgs`.
|
|
25
|
+
The first positional parameter is now the canonical write adapter; `audit_adapter`
|
|
26
|
+
(optional in args) falls back to it when omitted. Previous callers that passed
|
|
27
|
+
`app_adapter` inside the args object should remove that key.
|
|
28
|
+
- **Worker ISO timestamp normalization** — the `includes('T')` guard in `worker.ts`
|
|
29
|
+
failed to normalize no-timezone ISO strings. The guard now detects SQLite's
|
|
30
|
+
space-separated format via `includes(' ')`, guaranteeing all `occurred_at` values
|
|
31
|
+
stored in `hazo_audit_field` are well-formed ISO-8601 regardless of input format.
|
|
32
|
+
- **Test-app scripted scenarios** — `/revert_demo` and `/snapshot_demo` each have a
|
|
33
|
+
one-click "Run scripted scenario" button that exercises both fixes end-to-end.
|
|
34
|
+
|
|
35
|
+
## 2.0.0 — 2026-05-20
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- **`auditIntent(adapter, name, callback, opts?)`** server helper for grouping
|
|
40
|
+
multi-write transactions under a shared `correlation_id`. Writes opening +
|
|
41
|
+
closing `hazo_audit_intent` rows; nested calls reuse the outer `correlation_id`.
|
|
42
|
+
- **`snapshot(adapter, { table, recordId, asOf })`** server function: replays
|
|
43
|
+
`hazo_audit_field` events to compute field state at a timestamp.
|
|
44
|
+
- **`revert(adapter, { table, recordId, toTimestamp, actorUserId, reason })`**
|
|
45
|
+
server function: applies the inverse writes to restore a record. Wrapped in
|
|
46
|
+
its own `audit.revert` intent. Throws `RecordNotFoundError` when no history
|
|
47
|
+
exists.
|
|
48
|
+
- **`auditQuery(adapter, { table, recordId, fromTimestamp, toTimestamp })`**
|
|
49
|
+
server function: server-side history fetch (used internally by snapshot/revert).
|
|
50
|
+
- **`<AuditViewer />`** client component — cross-record admin viewer with CSV
|
|
51
|
+
export. Hits the new `viewer.GET` handler on `createAuditEventsRoutes`.
|
|
52
|
+
- **`<RevertConfirmDialog />`** client component — modal helper for confirming
|
|
53
|
+
a revert with a typed reason.
|
|
54
|
+
- New optional `viewer_permission` on `AuditEventsRoutesOptions`.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- Sample INI's default `exclude_tables` now includes `hazo_logs, hazo_notifications`.
|
|
59
|
+
- Sample INI now documents the deterministic capture matrix inline.
|
|
60
|
+
- The package now ships a jest test suite (31 tests across 7 scenarios).
|
|
61
|
+
- Worker now writes ISO-8601 `occurred_at` on field rows (was SQLite space-separated format).
|
|
62
|
+
|
|
63
|
+
### Not changed
|
|
64
|
+
|
|
65
|
+
- Database schema: no migrations beyond `001_init.sql`.
|
|
66
|
+
- Existing exports (`wrapWithAudit`, `startAuditWorker`, `createAuditedCrudService`,
|
|
67
|
+
`emitIntentEvent`, `runWithAuditContext`, `<FieldAuditIcon>`, `<FieldAuditTrail>`,
|
|
68
|
+
`createAuditEventsRoutes`) are unchanged and backward-compatible.
|
|
69
|
+
- INI remains the primary source of truth for capture rules.
|
|
70
|
+
|
|
71
|
+
### Deferred
|
|
72
|
+
|
|
73
|
+
- `replayAudit()` — moved to v2.1.0.
|
|
74
|
+
|
|
3
75
|
## v1.0.0 — 2026-05-20
|
|
4
76
|
|
|
5
77
|
Initial release. Implements PRD `design/PRD.md` end-to-end.
|
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ hazo_audit_field ◄──────────── /api/audit/events
|
|
|
72
72
|
|
|
73
73
|
| Import | What |
|
|
74
74
|
|---|---|
|
|
75
|
-
| `hazo_audit` | Client-safe types and permission constants (`AUDIT_VIEW_HISTORY`, etc.). |
|
|
75
|
+
| `hazo_audit` | Client-safe types and permission constants (`AUDIT_VIEW_HISTORY`, etc.). Also exports `OpLabels` interface and `DEFAULT_OP_LABELS` constant. |
|
|
76
76
|
| `hazo_audit/server` | `wrapWithAudit`, `startAuditWorker`, `runWithAuditContext`, `createAuditedCrudService`, `emitIntentEvent`. Server-only. |
|
|
77
77
|
| `hazo_audit/nextjs` | `createAuditEventsRoutes` — Next.js GET + reveal POST handlers. |
|
|
78
78
|
| `hazo_audit/client` | `<FieldAuditIcon />`, `<FieldAuditTrail />`. Safe in client components. |
|
|
@@ -172,6 +172,43 @@ await svc.updateById(folderId, patch, {
|
|
|
172
172
|
Direct Layer-1 intent emission (no piggyback). `withAudit(name, payload, fn)`
|
|
173
173
|
ergonomic is Phase 2.
|
|
174
174
|
|
|
175
|
+
### `OpLabels` / `DEFAULT_OP_LABELS`
|
|
176
|
+
|
|
177
|
+
Override the badge labels rendered on each event in `<FieldAuditTrail />`:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import { DEFAULT_OP_LABELS } from 'hazo_audit'
|
|
181
|
+
import { FieldAuditTrail } from 'hazo_audit/client'
|
|
182
|
+
|
|
183
|
+
// Keep defaults for insert/delete; rename update → "Edited"
|
|
184
|
+
<FieldAuditTrail
|
|
185
|
+
{...props}
|
|
186
|
+
opLabels={{ ...DEFAULT_OP_LABELS, update: 'Edited' }}
|
|
187
|
+
/>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Default labels: `insert → Added`, `update → Changed`, `delete → Removed`.
|
|
191
|
+
Pass an empty string for an op to fall back to the raw DB op.
|
|
192
|
+
|
|
193
|
+
### Intent labels (`intentLabels`)
|
|
194
|
+
|
|
195
|
+
When events are fired inside `auditIntent(adapter, name, callback)`, the
|
|
196
|
+
trail can annotate each event with a human-readable source label:
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
<FieldAuditTrail
|
|
200
|
+
{...props}
|
|
201
|
+
intentLabels={{
|
|
202
|
+
survey_prefill_key_info: 'auto-fill',
|
|
203
|
+
wp_pdf_prefill: 'PDF import',
|
|
204
|
+
}}
|
|
205
|
+
/>
|
|
206
|
+
// Renders: "Changed · Pubs Abayasiri (via auto-fill)"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The component fetches the correlated intent events automatically when
|
|
210
|
+
`intentLabels` is non-empty; no extra setup required.
|
|
211
|
+
|
|
175
212
|
### `createAuditEventsRoutes({ audit_adapter, getAuth })` → `{ GET, reveal: { POST } }`
|
|
176
213
|
|
|
177
214
|
Next.js route factory.
|
|
@@ -204,10 +241,29 @@ createAuditEventsRoutes({
|
|
|
204
241
|
Renders a clock icon that opens a popover with the field's audit trail.
|
|
205
242
|
Self-positioning, no Radix dep.
|
|
206
243
|
|
|
244
|
+
| Prop | Type | Default | Description |
|
|
245
|
+
|---|---|---|---|
|
|
246
|
+
| `subjectKind` | `string` | — | Required. Table-level subject kind (e.g. `"client_folder"`). |
|
|
247
|
+
| `subjectId` | `string` | — | Required. Record ID. |
|
|
248
|
+
| `fieldPath` | `string` | — | Field to scope the trail to. |
|
|
249
|
+
| `api_base` | `string` | `"/api/audit"` | Route prefix. |
|
|
250
|
+
| `opLabels` | `OpLabels` | `DEFAULT_OP_LABELS` | Override op badge text for individual ops. |
|
|
251
|
+
| `intentLabels` | `Record<string, string>` | — | Map of intent event names → display labels. Adds a "(via …)" annotation to events fired inside a named intent. |
|
|
252
|
+
|
|
207
253
|
### `<FieldAuditTrail subjectKind subjectId fieldPath? />`
|
|
208
254
|
|
|
209
255
|
Renders the trail directly (use in a sidebar, modal, etc.).
|
|
210
256
|
|
|
257
|
+
| Prop | Type | Default | Description |
|
|
258
|
+
|---|---|---|---|
|
|
259
|
+
| `subjectKind` | `string` | — | Required. |
|
|
260
|
+
| `subjectId` | `string` | — | Required. |
|
|
261
|
+
| `fieldPath` | `string` | — | Filter to one field. Omit for the full record trail. |
|
|
262
|
+
| `api_base` | `string` | `"/api/audit"` | Route prefix. |
|
|
263
|
+
| `opLabels` | `OpLabels` | `DEFAULT_OP_LABELS` | Override op badge text. See `OpLabels` + `DEFAULT_OP_LABELS`. |
|
|
264
|
+
| `intentLabels` | `Record<string, string>` | — | Annotate changes with their originating intent. Key = bare event name (`.completed`/`.failed` stripped). |
|
|
265
|
+
| `limit` | `number` | `50` | Max events to fetch. |
|
|
266
|
+
|
|
211
267
|
## Schema
|
|
212
268
|
|
|
213
269
|
Three tables (see `migrations/001_init.sql` for both Postgres + SQLite):
|
|
@@ -259,6 +315,87 @@ Sidebar walks through:
|
|
|
259
315
|
|
|
260
316
|
Backed by SQLite (sql.js); the demo DB lives at `test-app/data/demo.db`.
|
|
261
317
|
|
|
318
|
+
## What's new in v2.0.0
|
|
319
|
+
|
|
320
|
+
### `auditIntent(adapter, name, callback)` — group multi-write transactions
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
import { auditIntent, runWithAuditContext } from 'hazo_audit/server';
|
|
324
|
+
|
|
325
|
+
await runWithAuditContext({ actor_kind: 'user', actor_user_id: 'u1' }, () =>
|
|
326
|
+
auditIntent(adapter, 'person.merge', async () => {
|
|
327
|
+
await crud.update(personA.id, { ...mergedFields });
|
|
328
|
+
await crud.delete(personB.id);
|
|
329
|
+
}, { metadata: { reason: 'manual merge by admin' } }),
|
|
330
|
+
);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
All captured writes inside the callback share a `correlation_id`. An opening
|
|
334
|
+
`hazo_audit_intent` row is written when the callback starts; a closing row
|
|
335
|
+
(`person.merge.completed` or `person.merge.failed`) lands on completion or
|
|
336
|
+
throw. Nested calls reuse the outer `correlation_id`.
|
|
337
|
+
|
|
338
|
+
### `snapshot(adapter, { table, recordId, asOf })`
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
import { snapshot } from 'hazo_audit/server';
|
|
342
|
+
|
|
343
|
+
const snap = await snapshot(adapter, {
|
|
344
|
+
table: 'app_persons',
|
|
345
|
+
recordId: 'p1',
|
|
346
|
+
asOf: new Date('2026-05-01T10:00:00Z'),
|
|
347
|
+
});
|
|
348
|
+
// → { state: { name: 'Alice', email: 'a@x.com' }, deleted: false, exists: true }
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Replays `hazo_audit_field` events for the subject up to `asOf` and returns the
|
|
352
|
+
computed field state.
|
|
353
|
+
|
|
354
|
+
### `revert(app_adapter, { table, recordId, toTimestamp, reason })`
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
import { revert, RecordNotFoundError } from 'hazo_audit/server';
|
|
358
|
+
|
|
359
|
+
try {
|
|
360
|
+
const result = await revert(wrapped, {
|
|
361
|
+
audit_adapter: base, // optional; falls back to app_adapter when omitted
|
|
362
|
+
table: 'app_persons',
|
|
363
|
+
recordId: 'p1',
|
|
364
|
+
toTimestamp: new Date('2026-05-01T10:00:00Z'),
|
|
365
|
+
actorUserId: 'admin1',
|
|
366
|
+
reason: 'user-requested rollback',
|
|
367
|
+
});
|
|
368
|
+
// result.applied = 'insert' | 'update' | 'delete' | 'noop'
|
|
369
|
+
} catch (e) {
|
|
370
|
+
if (e instanceof RecordNotFoundError) { /* no audit history exists */ }
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Computes the target snapshot, diffs against the current row, and applies the
|
|
375
|
+
necessary PATCH/INSERT/DELETE — all wrapped in an `audit.revert` intent.
|
|
376
|
+
|
|
377
|
+
### `<AuditViewer />` (R3) — cross-record admin viewer
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
import { AuditViewer } from 'hazo_audit/client';
|
|
381
|
+
|
|
382
|
+
<AuditViewer
|
|
383
|
+
api_base="/api/audit"
|
|
384
|
+
initialFilters={{ subject_kind: 'person' }}
|
|
385
|
+
/>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Filterable, grouped-by-`correlation_id` list of all audit events with CSV export.
|
|
389
|
+
|
|
390
|
+
### `<RevertConfirmDialog />`
|
|
391
|
+
|
|
392
|
+
Modal helper for confirming a revert with a typed reason.
|
|
393
|
+
|
|
394
|
+
### Capture default exclusions widened (R2)
|
|
395
|
+
|
|
396
|
+
The sample INI now ships with `hazo_logs, hazo_notifications` in `exclude_tables`
|
|
397
|
+
by default. The capture matrix is documented inline in `config/hazo_audit_config.ini.sample`.
|
|
398
|
+
|
|
262
399
|
## Related
|
|
263
400
|
|
|
264
401
|
- `hazo_connect` — provides the adapter interface and `claimRows()` primitive.
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -184,3 +184,12 @@ wasn't set).
|
|
|
184
184
|
| `[retention]` | Default 30d for drained outbox, 90d for dead-lettered. Bump if you need longer auditability. |
|
|
185
185
|
| `[worker]` | Bump `poll_ms` down for snappier history (CPU cost: minimal at single-pod scale). |
|
|
186
186
|
| `[overrides.<table>]` | `sensitive_columns`, `jsonb_columns`, `jsonb_path_exclude`, `resolver`, `fanout_bulk_writes`. |
|
|
187
|
+
|
|
188
|
+
## Running the test suite
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm test
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The suite uses jest 30 + ts-jest with an in-memory SQLite adapter per test.
|
|
195
|
+
No external services or fixtures required. Total runtime under 30 seconds.
|
|
@@ -13,11 +13,21 @@ include_tables =
|
|
|
13
13
|
|
|
14
14
|
; Blacklist by prefix or exact name. Always wins over include rules.
|
|
15
15
|
exclude_table_prefixes = _
|
|
16
|
-
exclude_tables = hazo_chat_typing_indicators, hazo_worker_heartbeats
|
|
16
|
+
exclude_tables = hazo_chat_typing_indicators, hazo_worker_heartbeats, hazo_logs, hazo_notifications
|
|
17
17
|
|
|
18
|
-
;
|
|
19
|
-
; (
|
|
20
|
-
;
|
|
18
|
+
; ─── Capture matrix (R2) ────────────────────────────────────────────────────
|
|
19
|
+
; The capture decision honors this order (deterministic, exclude wins):
|
|
20
|
+
; 1. hazo_audit_outbox / hazo_audit_field / hazo_audit_intent → never (hardcoded)
|
|
21
|
+
; 2. exclude_tables → skip
|
|
22
|
+
; 3. exclude_table_prefixes → skip
|
|
23
|
+
; 4. include_tables → capture
|
|
24
|
+
; 5. include_table_prefixes → capture
|
|
25
|
+
; 6. otherwise → skip (default deny)
|
|
26
|
+
;
|
|
27
|
+
; To opt a single table into auditing without enabling the whole prefix,
|
|
28
|
+
; clear `include_table_prefixes` and add the table to `include_tables`.
|
|
29
|
+
; To suppress a single table inside a captured prefix, add it to
|
|
30
|
+
; `exclude_tables`.
|
|
21
31
|
|
|
22
32
|
[retention]
|
|
23
33
|
; Days to keep successfully-drained outbox rows before the reaper deletes them.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface AuditViewerProps {
|
|
2
|
+
api_base?: string;
|
|
3
|
+
initialFilters?: {
|
|
4
|
+
subject_kind?: string;
|
|
5
|
+
subject_id?: string;
|
|
6
|
+
actor_user_id?: string;
|
|
7
|
+
since?: string;
|
|
8
|
+
until?: string;
|
|
9
|
+
};
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function AuditViewer({ api_base, initialFilters, className, }: AuditViewerProps): JSX.Element;
|
|
13
|
+
//# sourceMappingURL=AuditViewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuditViewer.d.ts","sourceRoot":"","sources":["../../src/client/AuditViewer.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE;QACf,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAuB,EACvB,cAAmB,EACnB,SAAS,GACV,EAAE,gBAAgB,GAAG,GAAG,CAAC,OAAO,CA0HhC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { cn } from './cn.js';
|
|
5
|
+
export function AuditViewer({ api_base = '/api/audit', initialFilters = {}, className, }) {
|
|
6
|
+
const [filters, setFilters] = useState(initialFilters);
|
|
7
|
+
const [events, setEvents] = useState([]);
|
|
8
|
+
const [loading, setLoading] = useState(false);
|
|
9
|
+
const [error, setError] = useState(null);
|
|
10
|
+
async function load() {
|
|
11
|
+
setLoading(true);
|
|
12
|
+
setError(null);
|
|
13
|
+
try {
|
|
14
|
+
const params = new URLSearchParams();
|
|
15
|
+
for (const [k, v] of Object.entries(filters)) {
|
|
16
|
+
if (v)
|
|
17
|
+
params.set(k, v);
|
|
18
|
+
}
|
|
19
|
+
const res = await fetch(`${api_base}/viewer?${params.toString()}`);
|
|
20
|
+
if (!res.ok) {
|
|
21
|
+
setError(`HTTP ${res.status}`);
|
|
22
|
+
setEvents([]);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const body = await res.json();
|
|
26
|
+
setEvents(body.events ?? []);
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
setError(e instanceof Error ? e.message : 'unknown error');
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
setLoading(false);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
useEffect(() => { load(); /* eslint-disable-next-line */ }, []);
|
|
36
|
+
function exportCsv() {
|
|
37
|
+
const params = new URLSearchParams();
|
|
38
|
+
for (const [k, v] of Object.entries(filters))
|
|
39
|
+
if (v)
|
|
40
|
+
params.set(k, v);
|
|
41
|
+
params.set('format', 'csv');
|
|
42
|
+
window.open(`${api_base}/viewer?${params.toString()}`, '_blank');
|
|
43
|
+
}
|
|
44
|
+
const groups = new Map();
|
|
45
|
+
for (const e of events) {
|
|
46
|
+
const list = groups.get(e.correlation_id) ?? [];
|
|
47
|
+
list.push(e);
|
|
48
|
+
groups.set(e.correlation_id, list);
|
|
49
|
+
}
|
|
50
|
+
return (_jsxs("div", { className: cn('flex flex-col gap-3 rounded border border-slate-200 p-4', className), children: [_jsxs("div", { className: "flex flex-wrap gap-2 text-sm", children: [_jsx("input", { className: "rounded border px-2 py-1", placeholder: "subject_kind", value: filters.subject_kind ?? '', onChange: (e) => setFilters({ ...filters, subject_kind: e.target.value }) }), _jsx("input", { className: "rounded border px-2 py-1", placeholder: "actor_user_id", value: filters.actor_user_id ?? '', onChange: (e) => setFilters({ ...filters, actor_user_id: e.target.value }) }), _jsx("input", { className: "rounded border px-2 py-1", placeholder: "since (ISO)", value: filters.since ?? '', onChange: (e) => setFilters({ ...filters, since: e.target.value }) }), _jsx("input", { className: "rounded border px-2 py-1", placeholder: "until (ISO)", value: filters.until ?? '', onChange: (e) => setFilters({ ...filters, until: e.target.value }) }), _jsx("button", { onClick: load, className: "rounded bg-amber-500 px-3 py-1 text-white", children: loading ? 'Loading…' : 'Apply' }), _jsx("button", { onClick: exportCsv, className: "rounded border px-3 py-1", children: "Export CSV" })] }), error && _jsx("div", { className: "text-sm text-red-600", children: error }), _jsxs("div", { className: "flex flex-col gap-2", children: [[...groups.entries()].map(([cid, evs]) => (_jsxs("details", { className: "rounded border border-slate-100 bg-slate-50 p-2", children: [_jsxs("summary", { className: "cursor-pointer text-sm", children: [_jsx("span", { className: "font-mono text-xs text-slate-600", children: cid.slice(0, 8) }), ' · ', _jsxs("span", { children: [evs.length, " change", evs.length === 1 ? '' : 's'] }), ' · ', _jsxs("span", { children: [evs[0].subject_kind, " ", evs[0].subject_id] }), ' · ', _jsx("span", { className: "text-xs text-slate-500", children: evs[0].occurred_at })] }), _jsxs("table", { className: "mt-2 w-full text-xs", children: [_jsx("thead", { children: _jsxs("tr", { className: "text-left", children: [_jsx("th", { className: "pr-3", children: "field" }), _jsx("th", { className: "pr-3", children: "op" }), _jsx("th", { className: "pr-3", children: "before" }), _jsx("th", { className: "pr-3", children: "after" }), _jsx("th", { className: "pr-3", children: "actor" })] }) }), _jsx("tbody", { children: evs.map((e) => (_jsxs("tr", { className: "border-t", children: [_jsx("td", { className: "pr-3 font-mono", children: e.field_path }), _jsx("td", { className: "pr-3", children: e.op }), _jsx("td", { className: "pr-3", children: JSON.stringify(e.before_value) }), _jsx("td", { className: "pr-3", children: JSON.stringify(e.after_value) }), _jsx("td", { className: "pr-3", children: e.actor_user_id ?? '—' })] }, e.id))) })] })] }, cid))), events.length === 0 && !loading && (_jsx("div", { className: "text-sm text-slate-500", children: "No events match the current filters." }))] })] }));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=AuditViewer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuditViewer.js","sourceRoot":"","sources":["../../src/client/AuditViewer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldAuditIcon.d.ts","sourceRoot":"","sources":["../../src/client/FieldAuditIcon.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"FieldAuditIcon.d.ts","sourceRoot":"","sources":["../../src/client/FieldAuditIcon.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAmFtE"}
|
|
@@ -12,7 +12,7 @@ import { FieldAuditTrail } from './FieldAuditTrail.js';
|
|
|
12
12
|
* permission" hint.
|
|
13
13
|
*/
|
|
14
14
|
export function FieldAuditIcon(props) {
|
|
15
|
-
const { subjectKind, subjectId, fieldPath, api_base, className, label } = props;
|
|
15
|
+
const { subjectKind, subjectId, fieldPath, api_base, intentLabels, opLabels, className, label, } = props;
|
|
16
16
|
const [open, setOpen] = React.useState(false);
|
|
17
17
|
const rootRef = React.useRef(null);
|
|
18
18
|
React.useEffect(() => {
|
|
@@ -35,7 +35,7 @@ export function FieldAuditIcon(props) {
|
|
|
35
35
|
document.removeEventListener('keydown', onKey);
|
|
36
36
|
};
|
|
37
37
|
}, [open]);
|
|
38
|
-
return (_jsxs("div", { ref: rootRef, className: "relative inline-block", children: [_jsx("button", { type: "button", "aria-label": label ?? `View audit history for ${fieldPath}`, title: label ?? 'View audit history', onClick: () => setOpen((v) => !v), className: cn('inline-flex h-6 w-6 items-center justify-center rounded-full', 'text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700', 'focus:outline-none focus:ring-2 focus:ring-slate-400', 'dark:hover:bg-slate-800 dark:hover:text-slate-200', className), children: _jsx(ClockIcon, { className: "h-3.5 w-3.5" }) }), open && (_jsxs("div", { role: "dialog", "aria-label": "Audit history", className: cn('absolute right-0 z-50 mt-2 w-96 max-w-[calc(100vw-2rem)]', 'rounded-md border border-slate-200 bg-white p-3 shadow-lg', 'dark:border-slate-700 dark:bg-slate-900'), children: [_jsxs("div", { className: "mb-2 flex items-center justify-between", children: [_jsxs("h3", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: ["History \u00B7 ", fieldPath] }), _jsx("button", { type: "button", "aria-label": "Close", onClick: () => setOpen(false), className: "text-slate-400 hover:text-slate-700 dark:hover:text-slate-200", children: _jsx(CloseIcon, { className: "h-4 w-4" }) })] }), _jsx(FieldAuditTrail, { subjectKind: subjectKind, subjectId: subjectId, fieldPath: fieldPath, api_base: api_base })] }))] }));
|
|
38
|
+
return (_jsxs("div", { ref: rootRef, className: "relative inline-block", children: [_jsx("button", { type: "button", "aria-label": label ?? `View audit history for ${fieldPath}`, title: label ?? 'View audit history', onClick: () => setOpen((v) => !v), className: cn('inline-flex h-6 w-6 items-center justify-center rounded-full', 'text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-700', 'focus:outline-none focus:ring-2 focus:ring-slate-400', 'dark:hover:bg-slate-800 dark:hover:text-slate-200', className), children: _jsx(ClockIcon, { className: "h-3.5 w-3.5" }) }), open && (_jsxs("div", { role: "dialog", "aria-label": "Audit history", className: cn('absolute right-0 z-50 mt-2 w-96 max-w-[calc(100vw-2rem)]', 'rounded-md border border-slate-200 bg-white p-3 shadow-lg', 'dark:border-slate-700 dark:bg-slate-900'), children: [_jsxs("div", { className: "mb-2 flex items-center justify-between", children: [_jsxs("h3", { className: "text-sm font-semibold text-slate-900 dark:text-slate-100", children: ["History \u00B7 ", fieldPath] }), _jsx("button", { type: "button", "aria-label": "Close", onClick: () => setOpen(false), className: "text-slate-400 hover:text-slate-700 dark:hover:text-slate-200", children: _jsx(CloseIcon, { className: "h-4 w-4" }) })] }), _jsx(FieldAuditTrail, { subjectKind: subjectKind, subjectId: subjectId, fieldPath: fieldPath, api_base: api_base, intentLabels: intentLabels, opLabels: opLabels })] }))] }));
|
|
39
39
|
}
|
|
40
40
|
function ClockIcon({ className }) {
|
|
41
41
|
return (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className, "aria-hidden": true, children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("polyline", { points: "12 6 12 12 16 14" })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldAuditIcon.js","sourceRoot":"","sources":["../../src/client/FieldAuditIcon.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,MAAM,
|
|
1
|
+
{"version":3,"file":"FieldAuditIcon.js","sourceRoot":"","sources":["../../src/client/FieldAuditIcon.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,MAAM,EACJ,WAAW,EACX,SAAS,EACT,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,KAAK,GACN,GAAG,KAAK,CAAC;IACV,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAiB,IAAI,CAAC,CAAC;IAEnD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,UAAU,GAAG,CAAC,CAAa,EAAE,EAAE;YACnC,IAAI,CAAC,OAAO,CAAC,OAAO;gBAAE,OAAO;YAC7B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAc,CAAC;gBAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAClE,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,CAAC,CAAgB,EAAE,EAAE;YACjC,IAAI,CAAC,CAAC,GAAG,KAAK,QAAQ;gBAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACnD,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC5C,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YACtD,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACjD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,OAAO,CACL,eAAK,GAAG,EAAE,OAAO,EAAE,SAAS,EAAC,uBAAuB,aAClD,iBACE,IAAI,EAAC,QAAQ,gBACD,KAAK,IAAI,0BAA0B,SAAS,EAAE,EAC1D,KAAK,EAAE,KAAK,IAAI,oBAAoB,EACpC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EACjC,SAAS,EAAE,EAAE,CACX,8DAA8D,EAC9D,0EAA0E,EAC1E,sDAAsD,EACtD,mDAAmD,EACnD,SAAS,CACV,YAED,KAAC,SAAS,IAAC,SAAS,EAAC,aAAa,GAAG,GAC9B,EACR,IAAI,IAAI,CACP,eACE,IAAI,EAAC,QAAQ,gBACF,eAAe,EAC1B,SAAS,EAAE,EAAE,CACX,0DAA0D,EAC1D,2DAA2D,EAC3D,yCAAyC,CAC1C,aAED,eAAK,SAAS,EAAC,wCAAwC,aACrD,cAAI,SAAS,EAAC,0DAA0D,gCAC3D,SAAS,IACjB,EACL,iBACE,IAAI,EAAC,QAAQ,gBACF,OAAO,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAC7B,SAAS,EAAC,+DAA+D,YAEzE,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,GAC1B,IACL,EACN,KAAC,eAAe,IACd,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,GAClB,IACE,CACP,IACG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,SAAS,EAA0B;IACtD,OAAO,CACL,eACE,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,SAAS,EAAE,SAAS,kCAGpB,iBAAQ,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,GAAG,EACjC,mBAAU,MAAM,EAAC,kBAAkB,GAAG,IAClC,CACP,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,SAAS,EAA0B;IACtD,OAAO,CACL,eACE,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,SAAS,EAAE,SAAS,kCAGpB,eAAM,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,GAAG,EACtC,eAAM,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,GAAG,EAAC,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,GAAG,IAClC,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldAuditTrail.d.ts","sourceRoot":"","sources":["../../src/client/FieldAuditTrail.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FieldAuditTrail.d.ts","sourceRoot":"","sources":["../../src/client/FieldAuditTrail.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,GAAG,CAAC,OAAO,CAiNxE"}
|
|
@@ -2,14 +2,21 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { cn } from './cn.js';
|
|
5
|
+
import { DEFAULT_OP_LABELS } from '../index.js';
|
|
5
6
|
/**
|
|
6
7
|
* Renders an ordered list of field audit events for a subject (optionally
|
|
7
8
|
* filtered to a single field_path). Sensitive rows show "[redacted]" with a
|
|
8
9
|
* "Reveal" button that calls /audit/events/[id]/reveal.
|
|
9
10
|
*/
|
|
10
11
|
export function FieldAuditTrail(props) {
|
|
11
|
-
const { subjectKind, subjectId, fieldPath, api_base = '/api/audit', limit = 50, className, onRevealed, } = props;
|
|
12
|
-
const
|
|
12
|
+
const { subjectKind, subjectId, fieldPath, api_base = '/api/audit', intentLabels, opLabels, limit = 50, className, onRevealed, } = props;
|
|
13
|
+
const wantIntent = !!intentLabels && Object.keys(intentLabels).length > 0;
|
|
14
|
+
const [state, setState] = React.useState({
|
|
15
|
+
loading: true,
|
|
16
|
+
events: [],
|
|
17
|
+
intentByCorrelation: new Map(),
|
|
18
|
+
revealed: {},
|
|
19
|
+
});
|
|
13
20
|
React.useEffect(() => {
|
|
14
21
|
let cancelled = false;
|
|
15
22
|
setState((s) => ({ ...s, loading: true, error: undefined }));
|
|
@@ -20,6 +27,8 @@ export function FieldAuditTrail(props) {
|
|
|
20
27
|
});
|
|
21
28
|
if (fieldPath)
|
|
22
29
|
params.set('field_path', fieldPath);
|
|
30
|
+
if (wantIntent)
|
|
31
|
+
params.set('include', 'intent');
|
|
23
32
|
fetch(`${api_base}/events?${params.toString()}`, { credentials: 'include' })
|
|
24
33
|
.then(async (r) => {
|
|
25
34
|
if (r.status === 403) {
|
|
@@ -37,14 +46,35 @@ export function FieldAuditTrail(props) {
|
|
|
37
46
|
setState({
|
|
38
47
|
loading: false,
|
|
39
48
|
events: [],
|
|
49
|
+
intentByCorrelation: new Map(),
|
|
40
50
|
revealed: {},
|
|
41
51
|
error: 'You do not have permission to view audit history.',
|
|
42
52
|
});
|
|
43
53
|
return;
|
|
44
54
|
}
|
|
55
|
+
// Build correlation_id → intent map. When multiple events share a
|
|
56
|
+
// correlation_id (e.g. `name` + `name.completed`), prefer the bare
|
|
57
|
+
// started event since `.completed`/`.failed` carry lifecycle status
|
|
58
|
+
// rather than the user-meaningful source label.
|
|
59
|
+
const intentMap = new Map();
|
|
60
|
+
for (const ie of data.intent_events ?? []) {
|
|
61
|
+
const existing = intentMap.get(ie.correlation_id);
|
|
62
|
+
if (!existing) {
|
|
63
|
+
intentMap.set(ie.correlation_id, ie);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const existingIsLifecycle = existing.event_name.endsWith('.completed') ||
|
|
67
|
+
existing.event_name.endsWith('.failed');
|
|
68
|
+
const candidateIsLifecycle = ie.event_name.endsWith('.completed') ||
|
|
69
|
+
ie.event_name.endsWith('.failed');
|
|
70
|
+
if (existingIsLifecycle && !candidateIsLifecycle) {
|
|
71
|
+
intentMap.set(ie.correlation_id, ie);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
45
74
|
setState({
|
|
46
75
|
loading: false,
|
|
47
76
|
events: data.field_events ?? [],
|
|
77
|
+
intentByCorrelation: intentMap,
|
|
48
78
|
revealed: {},
|
|
49
79
|
});
|
|
50
80
|
})
|
|
@@ -54,6 +84,7 @@ export function FieldAuditTrail(props) {
|
|
|
54
84
|
setState({
|
|
55
85
|
loading: false,
|
|
56
86
|
events: [],
|
|
87
|
+
intentByCorrelation: new Map(),
|
|
57
88
|
revealed: {},
|
|
58
89
|
error: err.message,
|
|
59
90
|
});
|
|
@@ -61,7 +92,7 @@ export function FieldAuditTrail(props) {
|
|
|
61
92
|
return () => {
|
|
62
93
|
cancelled = true;
|
|
63
94
|
};
|
|
64
|
-
}, [subjectKind, subjectId, fieldPath, api_base, limit]);
|
|
95
|
+
}, [subjectKind, subjectId, fieldPath, api_base, limit, wantIntent]);
|
|
65
96
|
async function handleReveal(id) {
|
|
66
97
|
try {
|
|
67
98
|
const r = await fetch(`${api_base}/events/${id}/reveal`, {
|
|
@@ -96,11 +127,43 @@ export function FieldAuditTrail(props) {
|
|
|
96
127
|
if (state.events.length === 0) {
|
|
97
128
|
return (_jsx("div", { className: cn('py-3 text-center text-xs text-slate-400', className), children: "No history yet." }));
|
|
98
129
|
}
|
|
99
|
-
return (_jsx("ol", { className: cn('space-y-2 text-sm', className), children: state.events.map((ev) =>
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
130
|
+
return (_jsx("ol", { className: cn('space-y-2 text-sm', className), children: state.events.map((ev) => {
|
|
131
|
+
const sourceLabel = resolveIntentLabel(ev.correlation_id, state.intentByCorrelation, intentLabels);
|
|
132
|
+
const actor = ev.actor_label || ev.actor_user_id || ev.actor_kind;
|
|
133
|
+
return (_jsxs("li", { className: "rounded border border-slate-200 p-2 dark:border-slate-700", children: [_jsxs("div", { className: "mb-1 flex items-center justify-between gap-2 text-xs text-slate-500", children: [_jsxs("span", { children: [_jsx("span", { className: cn('mr-2 inline-block rounded px-1.5 py-0.5 text-[10px] font-semibold tracking-wide', ev.op === 'insert'
|
|
134
|
+
? 'bg-emerald-600 text-white dark:bg-emerald-500'
|
|
135
|
+
: ev.op === 'delete'
|
|
136
|
+
? 'bg-rose-600 text-white dark:bg-rose-500'
|
|
137
|
+
: 'bg-sky-600 text-white dark:bg-sky-500'), children: resolveOpLabel(ev.op, opLabels) }), actor, sourceLabel && (_jsxs("span", { className: "ml-1 text-slate-500 dark:text-slate-400", children: ["(via ", sourceLabel, ")"] }))] }), _jsx("time", { dateTime: ev.occurred_at, title: ev.occurred_at, className: "text-[11px] text-slate-400", children: formatDate(ev.occurred_at) })] }), !fieldPath && (_jsx("div", { className: "mb-1 font-mono text-xs text-slate-600 dark:text-slate-300", children: ev.field_path })), _jsx(ValueDiff, { event: ev, revealed: state.revealed[ev.id], onReveal: () => handleReveal(ev.id) })] }, ev.id));
|
|
138
|
+
}) }));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Resolve the friendly badge label for a field event op. Consumer-supplied
|
|
142
|
+
* overrides win; otherwise the package defaults (Added / Changed / Removed)
|
|
143
|
+
* apply. An explicit empty-string override falls back to the raw DB op so
|
|
144
|
+
* apps can opt into the legacy uppercase rendering per-op.
|
|
145
|
+
*/
|
|
146
|
+
function resolveOpLabel(op, overrides) {
|
|
147
|
+
const override = overrides?.[op];
|
|
148
|
+
if (override !== undefined)
|
|
149
|
+
return override === '' ? op : override;
|
|
150
|
+
return DEFAULT_OP_LABELS[op];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Look up an intent label for a field event by correlation_id. `.completed`
|
|
154
|
+
* and `.failed` suffixes are stripped so the app's `intentLabels` map only
|
|
155
|
+
* needs the bare event names.
|
|
156
|
+
*/
|
|
157
|
+
function resolveIntentLabel(correlation_id, intentByCorrelation, labels) {
|
|
158
|
+
if (!labels)
|
|
159
|
+
return undefined;
|
|
160
|
+
const intent = intentByCorrelation.get(correlation_id);
|
|
161
|
+
if (!intent)
|
|
162
|
+
return undefined;
|
|
163
|
+
const name = intent.event_name
|
|
164
|
+
.replace(/\.completed$/, '')
|
|
165
|
+
.replace(/\.failed$/, '');
|
|
166
|
+
return labels[name];
|
|
104
167
|
}
|
|
105
168
|
function ValueDiff({ event, revealed, onReveal, }) {
|
|
106
169
|
if (event.is_sensitive && !revealed) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldAuditTrail.js","sourceRoot":"","sources":["../../src/client/FieldAuditTrail.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAQ7B;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,MAAM,EACJ,WAAW,EACX,SAAS,EACT,SAAS,EACT,QAAQ,GAAG,YAAY,EACvB,KAAK,GAAG,EAAE,EACV,SAAS,EACT,UAAU,GACX,GAAG,KAAK,CAAC;IAEV,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,
|
|
1
|
+
{"version":3,"file":"FieldAuditTrail.js","sourceRoot":"","sources":["../../src/client/FieldAuditTrail.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface RevertConfirmDialogProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
table: string;
|
|
4
|
+
recordId: string;
|
|
5
|
+
toTimestamp: string;
|
|
6
|
+
onConfirm: (reason: string) => Promise<void>;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function RevertConfirmDialog({ open, table, recordId, toTimestamp, onConfirm, onClose, className, }: RevertConfirmDialogProps): JSX.Element | null;
|
|
11
|
+
//# sourceMappingURL=RevertConfirmDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RevertConfirmDialog.d.ts","sourceRoot":"","sources":["../../src/client/RevertConfirmDialog.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,WAAW,EACX,SAAS,EACT,OAAO,EACP,SAAS,GACV,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CA4D/C"}
|