@byline/host-tanstack-start 3.9.0 → 3.10.0
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/dist/admin-shell/collections/document-history.d.ts +53 -0
- package/dist/admin-shell/collections/document-history.js +103 -0
- package/dist/admin-shell/collections/document-history.module.js +9 -0
- package/dist/admin-shell/collections/document-history_module.css +28 -0
- package/dist/admin-shell/collections/history.d.ts +8 -1
- package/dist/admin-shell/collections/history.js +73 -29
- package/dist/admin-shell/collections/history.module.js +1 -0
- package/dist/admin-shell/collections/history_module.css +4 -0
- package/dist/routes/create-collection-history-route.js +23 -6
- package/dist/server-fns/collections/audit.d.ts +50 -0
- package/dist/server-fns/collections/audit.js +40 -0
- package/dist/server-fns/collections/index.d.ts +1 -0
- package/dist/server-fns/collections/index.js +1 -0
- package/package.json +8 -8
- package/src/admin-shell/collections/document-history.module.css +46 -0
- package/src/admin-shell/collections/document-history.tsx +156 -0
- package/src/admin-shell/collections/history.module.css +6 -0
- package/src/admin-shell/collections/history.tsx +331 -281
- package/src/routes/create-collection-history-route.tsx +25 -3
- package/src/server-fns/collections/audit.ts +97 -0
- package/src/server-fns/collections/index.ts +1 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useTranslation } from '@byline/i18n/react'
|
|
10
|
+
import { Container, Section, Table } from '@byline/ui/react'
|
|
11
|
+
import cx from 'classnames'
|
|
12
|
+
|
|
13
|
+
import styles from './document-history.module.css'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* One serialised audit-log entry as it reaches the admin UI. Mirrors
|
|
17
|
+
* `@byline/client`'s `AuditLogEntry` but with `occurredAt` as an ISO string —
|
|
18
|
+
* the value crosses the TanStack server-fn boundary through `serialise()`,
|
|
19
|
+
* which turns Dates into strings (docs/AUDIT.md — Workstream 3).
|
|
20
|
+
*/
|
|
21
|
+
export interface AuditLogEntryView {
|
|
22
|
+
id: string
|
|
23
|
+
documentId: string | null
|
|
24
|
+
collectionId: string | null
|
|
25
|
+
actorId: string | null
|
|
26
|
+
actorRealm: string
|
|
27
|
+
action: string
|
|
28
|
+
field: string | null
|
|
29
|
+
before: unknown
|
|
30
|
+
after: unknown
|
|
31
|
+
occurredAt: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The document-history payload attached to the history loader: the page of
|
|
36
|
+
* audit entries plus the admin-side resolved actor labels (`actors`, keyed by
|
|
37
|
+
* actor id — ids absent from the map belong to deleted users; system/tooling
|
|
38
|
+
* rows carry a NULL actorId).
|
|
39
|
+
*/
|
|
40
|
+
export interface DocumentHistoryData {
|
|
41
|
+
entries: AuditLogEntryView[]
|
|
42
|
+
meta: { total: number; page: number; pageSize: number; totalPages: number }
|
|
43
|
+
actors?: Record<string, { label: string }>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Maps namespaced audit `action` values to their i18n label keys. Unknown
|
|
48
|
+
* actions fall back to the raw value rather than a missing-key warning.
|
|
49
|
+
*/
|
|
50
|
+
const ACTION_KEYS: Record<string, string> = {
|
|
51
|
+
'document.path.changed': 'collections.documentHistory.actionPathChanged',
|
|
52
|
+
'document.locales.changed': 'collections.documentHistory.actionLocalesChanged',
|
|
53
|
+
'document.status.changed': 'collections.documentHistory.actionStatusChanged',
|
|
54
|
+
'document.deleted': 'collections.documentHistory.actionDeleted',
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Render an audit before/after value inline: arrays comma-join, nullish → em-dash. */
|
|
58
|
+
function formatAuditValue(value: unknown): string {
|
|
59
|
+
if (value == null) return '—'
|
|
60
|
+
if (Array.isArray(value)) return value.length > 0 ? value.join(', ') : '—'
|
|
61
|
+
return String(value)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Document-grain audit log for a single document (docs/AUDIT.md — Workstream
|
|
66
|
+
* 3, "Document history" tab): a chronological, newest-first list of the
|
|
67
|
+
* non-versioned changes the version stream does not record — path /
|
|
68
|
+
* available-locales writes, in-place status transitions, and the deletion
|
|
69
|
+
* event. No diff viewer; before/after render inline.
|
|
70
|
+
*/
|
|
71
|
+
export const DocumentHistoryView = ({ data }: { data: DocumentHistoryData }) => {
|
|
72
|
+
const { t } = useTranslation('byline-admin')
|
|
73
|
+
const entries = data?.entries ?? []
|
|
74
|
+
|
|
75
|
+
if (entries.length === 0) {
|
|
76
|
+
return (
|
|
77
|
+
<Section>
|
|
78
|
+
<Container>
|
|
79
|
+
<p className={cx('byline-coll-dochistory-empty', styles.empty)}>
|
|
80
|
+
{t('collections.documentHistory.empty')}
|
|
81
|
+
</p>
|
|
82
|
+
</Container>
|
|
83
|
+
</Section>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<Section>
|
|
89
|
+
<Container>
|
|
90
|
+
<Table.Container className={cx('byline-coll-dochistory-table-wrap', styles.tableWrap)}>
|
|
91
|
+
<Table>
|
|
92
|
+
<Table.Header>
|
|
93
|
+
<Table.Row>
|
|
94
|
+
<Table.HeadingCell scope="col">
|
|
95
|
+
{t('collections.documentHistory.colWhen')}
|
|
96
|
+
</Table.HeadingCell>
|
|
97
|
+
<Table.HeadingCell scope="col">
|
|
98
|
+
{t('collections.documentHistory.colAction')}
|
|
99
|
+
</Table.HeadingCell>
|
|
100
|
+
<Table.HeadingCell scope="col">
|
|
101
|
+
{t('collections.documentHistory.colActor')}
|
|
102
|
+
</Table.HeadingCell>
|
|
103
|
+
<Table.HeadingCell scope="col">
|
|
104
|
+
{t('collections.documentHistory.colChange')}
|
|
105
|
+
</Table.HeadingCell>
|
|
106
|
+
</Table.Row>
|
|
107
|
+
</Table.Header>
|
|
108
|
+
<Table.Body>
|
|
109
|
+
{entries.map((entry) => {
|
|
110
|
+
const actionKey = ACTION_KEYS[entry.action]
|
|
111
|
+
const actionLabel = actionKey ? t(actionKey) : entry.action
|
|
112
|
+
// System/tooling write (NULL actor or 'system' realm) → the
|
|
113
|
+
// system label; an unresolved id is a deleted user; otherwise
|
|
114
|
+
// the admin-resolved label.
|
|
115
|
+
const actorLabel =
|
|
116
|
+
entry.actorId == null || entry.actorRealm === 'system'
|
|
117
|
+
? t('collections.documentHistory.systemActor')
|
|
118
|
+
: (data.actors?.[entry.actorId]?.label ??
|
|
119
|
+
t('collections.history.audit.formerUser'))
|
|
120
|
+
// The deletion event carries no before/after; everything else
|
|
121
|
+
// renders "before → after".
|
|
122
|
+
const hasChange = entry.before != null || entry.after != null
|
|
123
|
+
return (
|
|
124
|
+
<Table.Row key={entry.id}>
|
|
125
|
+
<Table.Cell className={cx('byline-coll-dochistory-when', styles.when)}>
|
|
126
|
+
{new Date(entry.occurredAt).toLocaleString()}
|
|
127
|
+
</Table.Cell>
|
|
128
|
+
<Table.Cell>{actionLabel}</Table.Cell>
|
|
129
|
+
<Table.Cell>{actorLabel}</Table.Cell>
|
|
130
|
+
<Table.Cell className={cx('byline-coll-dochistory-change', styles.change)}>
|
|
131
|
+
{hasChange ? (
|
|
132
|
+
<>
|
|
133
|
+
<span className={cx('byline-coll-dochistory-before', styles.before)}>
|
|
134
|
+
{formatAuditValue(entry.before)}
|
|
135
|
+
</span>
|
|
136
|
+
<span className={cx('byline-coll-dochistory-arrow', styles.arrow)}>
|
|
137
|
+
{' → '}
|
|
138
|
+
</span>
|
|
139
|
+
<span className={cx('byline-coll-dochistory-after', styles.after)}>
|
|
140
|
+
{formatAuditValue(entry.after)}
|
|
141
|
+
</span>
|
|
142
|
+
</>
|
|
143
|
+
) : (
|
|
144
|
+
'—'
|
|
145
|
+
)}
|
|
146
|
+
</Table.Cell>
|
|
147
|
+
</Table.Row>
|
|
148
|
+
)
|
|
149
|
+
})}
|
|
150
|
+
</Table.Body>
|
|
151
|
+
</Table>
|
|
152
|
+
</Table.Container>
|
|
153
|
+
</Container>
|
|
154
|
+
</Section>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
@@ -67,6 +67,12 @@
|
|
|
67
67
|
background-color: var(--canvas-700);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/* Sub-view tab bar (Content versions / Document history — docs/AUDIT.md W3). */
|
|
71
|
+
.tabs,
|
|
72
|
+
:global(.byline-coll-history-tabs) {
|
|
73
|
+
margin-top: 0.25rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
70
76
|
.options,
|
|
71
77
|
:global(.byline-coll-history-options) {
|
|
72
78
|
display: flex;
|