@conduction/nextcloud-vue 2.148.0 → 2.149.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/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +24 -7
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +12 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +2 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js +23 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +34 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue.js +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue.js +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js +64 -8
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js.map +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js +14 -4
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +26 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +10 -2
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +84 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +61 -33
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +49 -2
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +90 -59
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue2.js +3 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +10 -0
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +11 -0
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +28 -21
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +3 -15
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +123 -115
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +4 -0
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +2 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +2 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +677 -444
- package/dist/nextcloud-vue.cjs.js +1336 -942
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +677 -444
- package/l10n/en.json +2 -1
- package/l10n/nl.json +2 -1
- package/package.json +1 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +24 -7
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +13 -1
- package/src/components/CnChecklistRunWidget/CnChecklistRunWidget.vue +29 -2
- package/src/components/CnDataTable/CnDataTable.vue +34 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +6 -1
- package/src/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue +1 -0
- package/src/components/CnDuplicateWarning/CnDuplicateWarning.vue +74 -10
- package/src/components/CnFactsWidget/CnFactsWidget.vue +35 -3
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +131 -3
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +103 -5
- package/src/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue +3 -1
- package/src/components/CnNotesCard/CnNotesCard.vue +10 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +16 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +1 -1
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +19 -19
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +4 -0
- package/src/css/dialog.css +17 -0
- package/src/css/look-board-detail.css +52 -3
- package/src/css/look-board-index.css +37 -1
- package/src/css/look-board.css +45 -5
- package/src/css/table.css +5 -2
|
@@ -2,7 +2,7 @@ import script from './CnAuditTrailCard.vue2.js';
|
|
|
2
2
|
import { render } from './CnAuditTrailCard.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-bd3033c8";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -121,6 +121,14 @@ var script = {
|
|
|
121
121
|
* @spec openspec/changes/audit-trail-exclude-actions/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-events-by-action
|
|
122
122
|
*/
|
|
123
123
|
excludeActions: { type: Array, default: () => [] },
|
|
124
|
+
/**
|
|
125
|
+
* Actors the card leaves out by user id (case-insensitive), such as
|
|
126
|
+
* `['System']` for a history of what people did: the bookkeeping a
|
|
127
|
+
* background job writes is not shown.
|
|
128
|
+
*
|
|
129
|
+
* @spec openspec/changes/audit-card-exclude-actors/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-entries-by-actor
|
|
130
|
+
*/
|
|
131
|
+
excludeActors: { type: Array, default: () => [] },
|
|
124
132
|
/** Whether the card collapses. */
|
|
125
133
|
collapsible: { type: Boolean, default: false },
|
|
126
134
|
/** Override the card title (defaults to the translated label). */
|
|
@@ -136,7 +144,8 @@ var script = {
|
|
|
136
144
|
/**
|
|
137
145
|
* What happened, in words, by action (`claim`) or by action and the
|
|
138
146
|
* state it led to (`complete:completed`, tried first). `{actor}`,
|
|
139
|
-
* `{state}` and `{changed.<key>}` (a value the entry recorded,
|
|
147
|
+
* `{state}` and `{changed.<key>}` (a value the entry recorded, a dotted key
|
|
148
|
+
* reading into it such as `{changed.data.fileName}`, in the
|
|
140
149
|
* words of `valueLabels`) are filled in; a label that names the actor leaves it off
|
|
141
150
|
* the line under it. An action without a label shows as written.
|
|
142
151
|
*
|
|
@@ -199,10 +208,17 @@ var script = {
|
|
|
199
208
|
/** @return {Array<object>} The entries without the excluded actions. */
|
|
200
209
|
shownEntries() {
|
|
201
210
|
const excluded = this.excludeActions.map((action) => String(action).toLowerCase());
|
|
202
|
-
|
|
211
|
+
const actors = this.excludeActors.map((actor) => String(actor).toLowerCase());
|
|
212
|
+
if (excluded.length === 0 && actors.length === 0) {
|
|
203
213
|
return this.entries
|
|
204
214
|
}
|
|
205
|
-
return this.entries.filter((entry) => !excluded.includes(String(entry.action || entry.event || '').toLowerCase())
|
|
215
|
+
return this.entries.filter((entry) => !excluded.includes(String(entry.action || entry.event || '').toLowerCase())
|
|
216
|
+
&& !actors.includes(String(entry.user || '').toLowerCase()))
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
/** @return {boolean} Whether the card leaves entries out, and so reads more than it shows. */
|
|
220
|
+
filtersEntries() {
|
|
221
|
+
return this.excludeActions.length > 0 || this.excludeActors.length > 0
|
|
206
222
|
},
|
|
207
223
|
|
|
208
224
|
displayedEntries() {
|
|
@@ -238,7 +254,7 @@ var script = {
|
|
|
238
254
|
if (this.sourceUrl !== null) {
|
|
239
255
|
return this.sourceUrl
|
|
240
256
|
}
|
|
241
|
-
const limit = this.
|
|
257
|
+
const limit = this.filtersEntries ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay;
|
|
242
258
|
const params = new URLSearchParams({ limit: String(limit) });
|
|
243
259
|
if (this.scope === 'app') {
|
|
244
260
|
if (this.register) {
|
|
@@ -318,7 +334,7 @@ var script = {
|
|
|
318
334
|
if (this.scope !== 'object' || this.sourceUrl !== null || !this.objectId || !Array.isArray(this.relatedSources)) {
|
|
319
335
|
return []
|
|
320
336
|
}
|
|
321
|
-
const limit = this.
|
|
337
|
+
const limit = this.filtersEntries ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay;
|
|
322
338
|
const read = async (url) => {
|
|
323
339
|
const response = await fetch(prefixUrl(url), { headers: buildHeaders() });
|
|
324
340
|
if (!response.ok) {
|
|
@@ -360,7 +376,7 @@ var script = {
|
|
|
360
376
|
return label
|
|
361
377
|
.replace('{actor}', this.actorName(entry))
|
|
362
378
|
.replace('{state}', entry.stateAfter || '')
|
|
363
|
-
.replace(/\{changed\.([\w
|
|
379
|
+
.replace(/\{changed\.([\w.-]+)\}/g, (match, key) => this.changedValue(entry, key))
|
|
364
380
|
.replace(/\{object\.([\w.-]+)\}/g, (match, path) => {
|
|
365
381
|
const value = this.object ? readPath(this.object, path) : undefined;
|
|
366
382
|
return value === null || value === undefined || typeof value === 'object' ? '' : String(value)
|
|
@@ -381,7 +397,8 @@ var script = {
|
|
|
381
397
|
*/
|
|
382
398
|
changedValue(entry, key) {
|
|
383
399
|
const changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {};
|
|
384
|
-
|
|
400
|
+
// A dotted key reads into what the entry recorded (`data.fileName` on a file action).
|
|
401
|
+
const value = String(key).split('.').reduce((at, part) => newValueOf(at !== null && typeof at === 'object' ? at[part] : undefined), changed);
|
|
385
402
|
if (value === null || value === undefined || typeof value === 'object') {
|
|
386
403
|
return ''
|
|
387
404
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAuditTrailCard.vue2.js","sources":["../../../../src/components/CnAuditTrailCard/CnAuditTrailCard.vue"],"sourcesContent":["<!--\n CnAuditTrailCard — compact audit-trail widget for the integration\n registry.\n\n Surface-aware shell around the `audit-trail` integration: fetches\n the object's recent audit-trail entries (query-time storage strategy\n per AD-22) and renders them in a CnDetailCard.\n\n Per umbrella change `pluggable-integration-registry` AD-19 (surface\n fallback), one component handles all surfaces — `surface` is\n forwarded so the component can branch internally if desired.\n-->\n<template>\n\t<CnDetailCard\n\t\t:title=\"resolvedTitle\"\n\t\t:icon=\"History\"\n\t\t:collapsible=\"collapsible\"\n\t\t:data-surface=\"surface\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<p v-else-if=\"failed\"\n\t\t\tclass=\"cn-audit-card__empty\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-audit-card-failed\">\n\t\t\t{{ failedLabel }}\n\t\t</p>\n\t\t<div v-else-if=\"shownEntries.length === 0\" class=\"cn-audit-card__empty\">\n\t\t\t{{ noEntriesLabel }}\n\t\t</div>\n\t\t<ul v-else class=\"cn-audit-card__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"entry in displayedEntries\"\n\t\t\t\t:key=\"entry.id\"\n\t\t\t\tclass=\"cn-audit-card__row\"\n\t\t\t\t:class=\"{ 'cn-audit-card__row--stacked': layout === 'stacked' }\">\n\t\t\t\t<div class=\"cn-audit-card__row-head\">\n\t\t\t\t\t<strong class=\"cn-audit-card__action\">{{ formatAction(entry) }}</strong>\n\t\t\t\t\t<span v-if=\"layout !== 'stacked'\" class=\"cn-audit-card__when\">{{ formatWhen(entry) }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-audit-card__row-body\">\n\t\t\t\t\t<span v-if=\"layout === 'stacked'\" class=\"cn-audit-card__when\" data-testid=\"cn-audit-card-when-below\">{{ stackedLine(entry) }}</span>\n\t\t\t\t\t<span v-else class=\"cn-audit-card__actor\">{{ formatActor(entry) }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"entry.authorized === false\"\n\t\t\t\t\t\tclass=\"cn-audit-card__refused\"\n\t\t\t\t\t\tdata-testid=\"cn-audit-card-refused\">{{ refusedLabel }}</span>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"entry.reason\" class=\"cn-audit-card__reason\">\n\t\t\t\t\t{{ entry.reason }}\n\t\t\t\t</p>\n\t\t\t</li>\n\t\t</ul>\n\t\t<p v-if=\"footnote\" class=\"cn-audit-card__footnote\" data-testid=\"cn-audit-trail-widget-footnote\">\n\t\t\t{{ footnote }}\n\t\t</p>\n\t\t<template v-if=\"shownEntries.length > maxDisplay\" #footer>\n\t\t\t<button class=\"cn-audit-card__show-all\" @click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ shownEntries.length }})\n\t\t\t</button>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport History from 'vue-material-design-icons/History.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport { formatBoardDate, formatTimeOfDay } from '../../utils/boardDate.js'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { leafSourceUrl } from '../../utils/leafSourceUrl.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { userDisplayName } from '../../utils/userDisplayName.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * A changed value as an entry records it: OpenRegister writes `{ old, new }`,\n * other sources the value itself.\n *\n * @param {unknown} value The recorded change.\n * @return {unknown} The value it changed to.\n */\nfunction newValueOf(value) {\n\treturn value !== null && typeof value === 'object' && Object.hasOwn(value, 'new') ? value.new : value\n}\n\n/**\n * @param {object} entry An audit entry.\n * @return {number} When it happened, in ms; 0 when unreadable.\n */\nfunction entryTime(entry) {\n\tconst time = new Date(entry.creationDateTime || entry.created || entry.timestamp || 0).getTime()\n\treturn Number.isNaN(time) ? 0 : time\n}\n\n/**\n * CnAuditTrailCard — compact audit-trail widget rendered by the\n * integration registry on dashboard and detail surfaces.\n *\n * Basic usage\n * ```vue\n * <CnAuditTrailCard\n * :register=\"registerId\"\n * :schema=\"schemaId\"\n * :object-id=\"objectId\"\n * surface=\"detail-page\" />\n * ```\n */\nexport default {\n\tname: 'CnAuditTrailCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon },\n\n\tprops: {\n\t\t/**\n\t\t * A muted line under the trail, inside the card (\"Kenmerk ZT-OMV-REG\").\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-footnote/specs/audit-trail/spec.md#requirement-a-history-card-can-end-in-a-line-about-the-record\n\t\t */\n\t\tfootnote: { type: String, default: '' },\n\t\t/** OpenRegister register id (slug or uuid). Optional for `scope: \"app\"`. */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). Optional for `scope: \"app\"`. */\n\t\tschema: { type: String, default: '' },\n\t\t/** Parent object id. Required for `scope: \"object\"` (the default); unused for `scope: \"app\"`. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/**\n\t\t * What the card lists. `object` (the default) is one object's trail\n\t\t * and needs `register`, `schema` and `objectId`. `app` is the\n\t\t * app-wide feed: the entries of every object the caller may read\n\t\t * (OpenRegister's `/audit-trails/readable`), narrowed to `register`\n\t\t * and `schema` when those are set.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t */\n\t\tscope: {\n\t\t\ttype: String,\n\t\t\tdefault: 'object',\n\t\t\tvalidator: (value) => ['object', 'app'].includes(value),\n\t\t},\n\n\t\t/** Rendering surface — passed for AD-19 surface fallback consumers. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (value) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(value),\n\t\t},\n\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\n\t\t/**\n\t\t * Read the trail of something that is not an OpenRegister object:\n\t\t * `{ kind: 'flow-task', id }` reads `${apiBase}/flow-tasks/{id}/audit`,\n\t\t * oldest first. `id` may be left out or written `@objectId`.\n\t\t *\n\t\t * @type {{kind: string, id?: (string|number)}|null}\n\t\t */\n\t\tsource: { type: Object, default: null },\n\n\t\t/** A trail URL that replaces the object's own; `{id}` is filled with the source's id or `objectId`. */\n\t\tendpoint: { type: String, default: '' },\n\n\t\t/** `newest` first (the object trail's order) or `oldest` first; empty takes `oldest` for a source and `newest` otherwise. */\n\t\torder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t\tvalidator: (value) => ['', 'newest', 'oldest'].includes(value),\n\t\t},\n\n\t\t/** Maximum rows to render. */\n\t\tmaxDisplay: { type: Number, default: 5 },\n\t\t/**\n\t\t * `stacked` (DqTaak \"Historie\"): the action, then one muted line under\n\t\t * it with the moment (\"6 okt 09:05\") and who, when the action does not\n\t\t * already name them. Default: the moment beside the action, who under it.\n\t\t */\n\t\tlayout: { type: String, default: '' },\n\t\t/**\n\t\t * Actions the card leaves out (case-insensitive), such as `['read']`\n\t\t * for a history of what changed. It then reads more entries than it\n\t\t * shows, so the rows it leaves out do not crowd the rest away.\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-exclude-actions/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-events-by-action\n\t\t */\n\t\texcludeActions: { type: Array, default: () => [] },\n\t\t/** Whether the card collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Pre-translated empty label. */\n\t\tnoEntriesLabel: { type: String, default: () => t('nextcloud-vue', 'No audit entries yet') },\n\t\t/** Pre-translated overflow label. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/** Pre-translated fallback action label. */\n\t\tactionLabel: { type: String, default: () => t('nextcloud-vue', 'Change') },\n\t\t/** Shown on an entry the server refused (`authorized: false`). */\n\t\trefusedLabel: { type: String, default: () => t('nextcloud-vue', '(refused)') },\n\t\t/**\n\t\t * What happened, in words, by action (`claim`) or by action and the\n\t\t * state it led to (`complete:completed`, tried first). `{actor}`,\n\t\t * `{state}` and `{changed.<key>}` (a value the entry recorded, in the\n\t\t * words of `valueLabels`) are filled in; a label that names the actor leaves it off\n\t\t * the line under it. An action without a label shows as written.\n\t\t *\n\t\t * @type {Object<string, string>|null}\n\t\t */\n\t\tactionLabels: { type: Object, default: null },\n\t\t/**\n\t\t * Words for the values an action label quotes as `{changed.<key>}`:\n\t\t * `{ purpose: { handling: 'Handling' } }`. A value without an entry\n\t\t * shows as written.\n\t\t *\n\t\t * @type {{[key: string]: {[value: string]: string}}|null}\n\t\t */\n\t\tvalueLabels: { type: Object, default: null },\n\t\t/**\n\t\t * What happened, in words, by the field an entry changed: rules\n\t\t * `[{ action?, field, to?, label }]`, the first whose `field` the entry\n\t\t * changed (to `to`, when given) wins over `actionLabels`. A label fills\n\t\t * the same tokens, plus `{object.<path>}` from `object`\n\t\t * (\"Version {object.version} published\" for `isDraft` set to false).\n\t\t *\n\t\t * @type {Array<{action?: string, field: string, to?: unknown, label: string}>}\n\t\t */\n\t\tchangeLabels: { type: Array, default: () => [] },\n\t\t/** The audited record, for `{object.<path>}` in a label; null without one. */\n\t\tobject: { type: Object, default: null },\n\t\t/**\n\t\t * Records beside the object whose events belong in its history:\n\t\t * `[{ as, register, schema, filter, limit? }]`. The card lists the\n\t\t * objects matching `filter` (`@objectId` is this object; at most\n\t\t * `limit`, default 5), reads their trails and merges the entries with\n\t\t * the object's own, newest first. A related entry is labelled by\n\t\t * `actionLabels[\"<as>.<action>\"]` first. Object scope only.\n\t\t *\n\t\t * @type {Array<{as: string, register: string, schema: string, filter?: object, limit?: number}>}\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\trelatedSources: { type: Array, default: () => [] },\n\t\t/** Shown when a `source` or `endpoint` read failed. */\n\t\tfailedLabel: { type: String, default: () => t('nextcloud-vue', 'The history could not be loaded') },\n\t},\n\n\temits: ['show-all'],\n\n\tdata() {\n\t\treturn {\n\t\t\tHistory: markRaw(History),\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\t/** A `source` or `endpoint` read failed: said, rather than shown as an empty trail. */\n\t\t\tfailed: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Audit trail')\n\t\t},\n\n\t\t/** @return {Array<object>} The entries without the excluded actions. */\n\t\tshownEntries() {\n\t\t\tconst excluded = this.excludeActions.map((action) => String(action).toLowerCase())\n\t\t\tif (excluded.length === 0) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.filter((entry) => !excluded.includes(String(entry.action || entry.event || '').toLowerCase()))\n\t\t},\n\n\t\tdisplayedEntries() {\n\t\t\tconst entries = this.oldestFirst ? [...this.shownEntries].sort((a, b) => entryTime(a) - entryTime(b)) : this.shownEntries\n\t\t\treturn entries.slice(0, this.maxDisplay)\n\t\t},\n\n\t\t/**\n\t\t * The trail URL a `source` or `endpoint` names, '' while its record id\n\t\t * is unknown, or null when the card reads an object.\n\t\t *\n\t\t * @return {string|null}\n\t\t * @spec openspec/changes/leaf-cards-read-a-source/specs/leaf-cards-read-a-source/spec.md#requirement-a-leaf-card-reads-a-source-or-an-endpoint\n\t\t */\n\t\tsourceUrl() {\n\t\t\treturn leafSourceUrl({ source: this.source, endpoint: this.endpoint, apiBase: this.apiBase, objectId: this.objectId }, 'audit')\n\t\t},\n\n\t\t/** @return {boolean} Whether the entries read oldest first. */\n\t\toldestFirst() {\n\t\t\treturn this.order === 'oldest' || (this.order === '' && this.sourceUrl !== null)\n\t\t},\n\n\t\t/**\n\t\t * The path the card reads (prefixed at fetch time), or '' when it has nothing to read: the\n\t\t * object's own trail, or the app-wide readable feed narrowed to the\n\t\t * register and schema when set.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {string}\n\t\t */\n\t\tfetchUrl() {\n\t\t\tif (this.sourceUrl !== null) {\n\t\t\t\treturn this.sourceUrl\n\t\t\t}\n\t\t\tconst limit = this.excludeActions.length > 0 ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay\n\t\t\tconst params = new URLSearchParams({ limit: String(limit) })\n\t\t\tif (this.scope === 'app') {\n\t\t\t\tif (this.register) {\n\t\t\t\t\tparams.set('register', this.register)\n\t\t\t\t}\n\t\t\t\tif (this.schema) {\n\t\t\t\t\tparams.set('schema', this.schema)\n\t\t\t\t}\n\t\t\t\treturn `${this.apiBase}/audit-trails/readable?${params.toString()}`\n\t\t\t}\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails?${params.toString()}`\n\t\t},\n\t},\n\n\twatch: {\n\t\tfetchUrl: {\n\t\t\timmediate: true,\n\t\t\thandler(url) {\n\t\t\t\tif (url) {\n\t\t\t\t\tthis.fetchEntries()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the entries from `fetchUrl`. The readable feed answers\n\t\t * `{ rows, nextCursor }`, the object trail `{ results }`.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchEntries() {\n\t\t\tconst url = this.fetchUrl\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst list = data.results || data.rows || data\n\t\t\t\t\tconst own = Array.isArray(list) ? list : []\n\t\t\t\t\tconst related = await this.fetchRelatedEntries()\n\t\t\t\t\tthis.entries = related.length > 0\n\t\t\t\t\t\t? [...own, ...related].sort((a, b) => entryTime(b) - entryTime(a))\n\t\t\t\t\t\t: own\n\t\t\t\t} else {\n\t\t\t\t\tthis.entries = []\n\t\t\t\t\tthis.failed = this.sourceUrl !== null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnAuditTrailCard] failed to fetch audit trail', err)\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.failed = this.sourceUrl !== null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The entries of the records beside the object (`relatedSources`),\n\t\t * each tagged with its source's `as`. A read that fails leaves that\n\t\t * source out.\n\t\t *\n\t\t * @return {Promise<Array<object>>} The entries.\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\tasync fetchRelatedEntries() {\n\t\t\tif (this.scope !== 'object' || this.sourceUrl !== null || !this.objectId || !Array.isArray(this.relatedSources)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst limit = this.excludeActions.length > 0 ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay\n\t\t\tconst read = async (url) => {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(String(response.status))\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = data.results || data.rows || data\n\t\t\t\treturn Array.isArray(list) ? list : []\n\t\t\t}\n\t\t\tconst perSource = await Promise.all(this.relatedSources\n\t\t\t\t.filter((source) => source && source.register && source.schema)\n\t\t\t\t.map(async (source) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst params = new URLSearchParams({ _limit: String(Number(source.limit) > 0 ? Number(source.limit) : 5), _order: JSON.stringify({ '@self.created': 'DESC' }) })\n\t\t\t\t\t\tfor (const [key, value] of Object.entries(source.filter || {})) {\n\t\t\t\t\t\t\tparams.set(key, value === '@objectId' ? this.objectId : String(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst objects = await read(`${this.apiBase}/objects/${source.register}/${source.schema}?${params.toString()}`)\n\t\t\t\t\t\tconst ids = objects.map((object) => object?.id || object?.['@self']?.id || object?.uuid).filter(Boolean)\n\t\t\t\t\t\tconst trails = await Promise.all(ids.map((id) => read(`${this.apiBase}/objects/${source.register}/${source.schema}/${id}/audit-trails?limit=${limit}`).catch(() => [])))\n\t\t\t\t\t\treturn trails.flat().map((entry) => ({ ...entry, relatedAs: source.as || source.schema }))\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn []\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\treturn perSource.flat()\n\t\t},\n\n\t\t/**\n\t\t * What happened: the action, with the state it led to when the entry\n\t\t * names one (a flow task's `stateAfter`).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t */\n\t\tformatAction(entry) {\n\t\t\tconst label = this.changeLabelFor(entry) ?? this.labelFor(entry)\n\t\t\tif (label !== null) {\n\t\t\t\treturn label\n\t\t\t\t\t.replace('{actor}', this.actorName(entry))\n\t\t\t\t\t.replace('{state}', entry.stateAfter || '')\n\t\t\t\t\t.replace(/\\{changed\\.([\\w-]+)\\}/g, (match, key) => this.changedValue(entry, key))\n\t\t\t\t\t.replace(/\\{object\\.([\\w.-]+)\\}/g, (match, path) => {\n\t\t\t\t\t\tconst value = this.object ? readPath(this.object, path) : undefined\n\t\t\t\t\t\treturn value === null || value === undefined || typeof value === 'object' ? '' : String(value)\n\t\t\t\t\t})\n\t\t\t}\n\t\t\tconst action = entry.action || entry.event || this.actionLabel\n\t\t\treturn entry.stateAfter ? `${action} (${entry.stateAfter})` : action\n\t\t},\n\n\t\t/**\n\t\t * A value the entry recorded under `changed` (an audit entry's context),\n\t\t * in the words of `valueLabels`; '' when it recorded none.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {string} key The recorded key.\n\t\t * @return {string} The value in words.\n\t\t * @spec openspec/changes/audit-label-changed-values/specs/audit-trail/spec.md#requirement-a-trail-label-can-quote-what-the-entry-recorded\n\t\t */\n\t\tchangedValue(entry, key) {\n\t\t\tconst changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {}\n\t\t\tconst value = newValueOf(changed[key])\n\t\t\tif (value === null || value === undefined || typeof value === 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst words = this.valueLabels && this.valueLabels[key]\n\t\t\treturn words && typeof words[value] === 'string' ? words[value] : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The `changeLabels` rule an entry matches: the first whose field the\n\t\t * entry changed, for its action and to its value when the rule names them.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string|null} The label, or null when no rule matches.\n\t\t */\n\t\tchangeLabelFor(entry) {\n\t\t\tconst changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {}\n\t\t\tconst action = entry.action || entry.event || ''\n\t\t\tfor (const rule of Array.isArray(this.changeLabels) ? this.changeLabels : []) {\n\t\t\t\tif (!rule || typeof rule.label !== 'string' || rule.label === '' || typeof rule.field !== 'string' || !Object.hasOwn(changed, rule.field)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (rule.action && rule.action !== action) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (Object.hasOwn(rule, 'to') && String(newValueOf(changed[rule.field])) !== String(rule.to)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn rule.label\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The `actionLabels` entry for an entry: by action and state first,\n\t\t * then by action.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string|null} The label, or null when none is declared.\n\t\t * @spec openspec/changes/audit-trail-action-labels/specs/audit-trail/spec.md#requirement-a-trail-can-say-what-happened-in-words\n\t\t */\n\t\tlabelFor(entry) {\n\t\t\tconst labels = this.actionLabels\n\t\t\tconst action = entry.action || entry.event\n\t\t\tif (!labels || !action) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst state = entry.stateAfter || ''\n\t\t\tconst prefix = entry.relatedAs ? `${entry.relatedAs}.` : ''\n\t\t\tconst label = (prefix ? (labels[`${prefix}${action}:${state}`] ?? labels[`${prefix}${action}`]) : undefined)\n\t\t\t\t?? labels[`${action}:${state}`] ?? labels[action]\n\t\t\treturn typeof label === 'string' && label !== '' ? label : null\n\t\t},\n\n\t\t/**\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} Who did it, by name where the entry carries one.\n\t\t */\n\t\tactorName(entry) {\n\t\t\tif (entry.actorDisplayName) {\n\t\t\t\treturn entry.actorDisplayName\n\t\t\t}\n\t\t\tconst id = entry.actor || entry.userId || entry.user || ''\n\t\t\t// A person's user id reads as their display name once it is known.\n\t\t\treturn (id && (!entry.performerType || entry.performerType === 'user') && userDisplayName(String(id))) || id\n\t\t},\n\n\t\t/**\n\t\t * The muted line of a stacked row: the moment in the board's short\n\t\t * form (\"6 okt 09:05\") and who, unless the action names them already.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t * @spec openspec/changes/audit-card-stacked-rows/specs/audit-trail/spec.md#requirement-an-audit-row-can-put-its-moment-under-the-action\n\t\t */\n\t\tstackedLine(entry) {\n\t\t\tconst raw = entry.creationDateTime || entry.created || entry.timestamp\n\t\t\tconst date = raw ? new Date(raw) : null\n\t\t\tconst when = date && !Number.isNaN(date.getTime()) ? `${formatBoardDate(date)} ${formatTimeOfDay(date)}` : ''\n\t\t\treturn [when, this.formatActor(entry)].filter((part) => part !== '').join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * Who did it: the actor, the kind of performer when it is not a\n\t\t * person (a flow, the system), and on whose behalf.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t */\n\t\tformatActor(entry) {\n\t\t\tconst named = (this.labelFor(entry) || '').includes('{actor}')\n\t\t\tconst parts = [named ? '' : this.actorName(entry)]\n\t\t\tif (entry.performerType && entry.performerType !== 'user') {\n\t\t\t\tparts.push(`(${entry.performerType})`)\n\t\t\t}\n\t\t\tif (entry.onBehalfOf) {\n\t\t\t\tparts.push(t('nextcloud-vue', 'on behalf of {name}', { name: entry.onBehalfOf }))\n\t\t\t}\n\t\t\treturn parts.filter((part) => part !== '').join(' ')\n\t\t},\n\n\t\tformatWhen(entry) {\n\t\t\tconst raw = entry.creationDateTime || entry.created || entry.timestamp\n\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst d = new Date(raw)\n\t\t\tif (Number.isNaN(d.getTime()) === true) {\n\t\t\t\treturn String(raw)\n\t\t\t}\n\t\t\treturn d.toLocaleString(userLocale())\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-audit-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-audit-card__row {\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-audit-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-audit-card__row-head {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-audit-card__action {\n\tcolor: var(--color-main-text);\n}\n\n.cn-audit-card__when {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\twhite-space: nowrap;\n}\n\n.cn-audit-card__row-body {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-audit-card__refused {\n\tmargin-inline-start: 6px;\n\tfont-weight: 700;\n\tcolor: var(--color-error-text, var(--color-main-text));\n}\n\n.cn-audit-card__reason {\n\tmargin: 2px 0 0;\n\tfont-size: 0.9em;\n\toverflow-wrap: anywhere;\n}\n\n.cn-audit-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n\n.cn-audit-card__footnote {\n\tmargin: 12px 0 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-audit-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tcursor: pointer;\n\tpadding: 4px 0;\n\tfont: inherit;\n}\n\n.cn-audit-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDetailCard","t"],"mappings":";;;;;;;;;;;;AA2EA;AACC;;AAEA;AACA;AACA;;AAED,SAAS,UAAU,CAAC,KAAK,EAAE;AAC1B,CAAA,OAAO,KAAI,KAAM,QAAQ,OAAO,KAAI,KAAM,QAAO,IAAK,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,IAAI,KAAK,CAAC,GAAE,GAAI,KAAI;AACrG,CAAA;;AAEA;AACC;;;AAGD,SAAS,SAAS,CAAC,KAAK,EAAE;AACzB,CAAA,MAAM,IAAG,GAAI,IAAI,IAAI,CAAC,KAAK,CAAC,oBAAoB,KAAK,CAAC,OAAM,IAAK,KAAK,CAAC,SAAQ,IAAK,CAAC,CAAC,CAAC,OAAO,GAAC;AAC/F,CAAA,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAE,GAAE,CAAE,GAAE,IAAG;AACpC,CAAA;;AAEA;;;AAGC;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAED,aAAe;CACd,IAAI,EAAE,kBAAkB;;AAExB,CAAA,UAAU,EAAE,gBAAEA,UAAY,EAAE,eAAe;;AAE3C,CAAA,KAAK,EAAE;AACN;;AAEC;AACA;;AAED,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACvC;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACvC;AACA,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACrC;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACvC;;;;;;AAMC;AACA;;AAED,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,QAAQ;GACjB,SAAS,EAAE,CAAC,KAAK,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;GACvD;;;AAGD,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,aAAa;GACtB,SAAS,EAAE,CAAC,KAAK,KAAK,CAAC,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;GACzG;;AAED;EACA,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAuB,EAAG;;AAE5D;;AAEC;;AAEA;AACA;;AAED,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;AAEvC;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;;;AAGvC,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX,SAAS,EAAE,CAAC,KAAK,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;GAC9D;;;AAGD,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG;AACxC;;;;;AAKA,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACrC;;;;AAIC;AACA;;AAED,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI;;AAElD,EAAA,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;;AAE9C,EAAA,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAC,EAAG;;AAEpC,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,sBAAsB,GAAG;AAC3F;AACA,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,UAAU,GAAG;AAC7E;AACA,EAAA,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,QAAQ,GAAG;;AAE1E,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;AAC9E;;;;AAIC;;AAEA;AACA;;AAED,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;AAC7C;;;AAGC;AACA;;;AAGD,EAAA,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;AAC5C;;;;;;AAMC;AACA;;AAED,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI;AAChD;AACA,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;AACvC;;;;;;;AAOC;AACA;AACA;;AAED,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI;AAClD;AACA,EAAA,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,iCAAiC,GAAG;EACnG;;AAED,CAAA,KAAK,EAAE,CAAC,UAAU,CAAC;;AAEnB,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;GACN,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;GACzB,OAAO,EAAE,EAAE;GACX,OAAO,EAAE,KAAK;AACd;GACA,MAAM,EAAE,KAAK;AACd,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT,EAAA,aAAa,GAAG;GACf,OAAO,IAAI,CAAC,KAAM,IAAGA,SAAC,CAAC,eAAe,EAAE,aAAa,CAAA;GACrD;;AAED;AACA,EAAA,YAAY,GAAG;AACd,GAAA,MAAM,QAAO,GAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAA;GACjF,IAAI,QAAQ,CAAC,WAAW,CAAC,EAAE;AAC1B,IAAA,OAAO,IAAI,CAAC,OAAM;AACnB,IAAA;GACA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,MAAK,IAAK,KAAK,CAAC,KAAI,IAAK,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;GACjH;;AAED,EAAA,gBAAgB,GAAG;GAClB,MAAM,OAAM,GAAI,IAAI,CAAC,WAAU,GAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC,CAAA,GAAI,SAAS,CAAC,CAAC,CAAC,CAAA,GAAI,IAAI,CAAC,aAAW;AACxH,GAAA,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAA;GACvC;;AAED;;AAEC;AACA;AACA;AACA;;EAED,SAAS,GAAG;GACX,OAAO,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAO,EAAG,EAAE,OAAO,CAAA;GAC9H;;;EAGD,WAAW,GAAG;AACb,GAAA,OAAO,IAAI,CAAC,KAAI,KAAM,QAAO,KAAM,IAAI,CAAC,KAAI,KAAM,EAAG,IAAG,IAAI,CAAC,SAAU,KAAI,IAAI,CAAA;GAC/E;;AAED;AACC;;;AAGA;AACA;AACA;;EAED,QAAQ,GAAG;GACV,IAAI,IAAI,CAAC,SAAQ,KAAM,IAAI,EAAE;AAC5B,IAAA,OAAO,IAAI,CAAC,SAAQ;AACrB,IAAA;AACA,GAAA,MAAM,KAAI,GAAI,IAAI,CAAC,cAAc,CAAC,MAAK,GAAI,CAAE,GAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE,CAAE,GAAE,IAAI,CAAC,WAAS;GACnG,MAAM,MAAO,GAAE,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAA,EAAG,EAAA;GAC3D,IAAI,IAAI,CAAC,KAAM,KAAI,KAAK,EAAE;AACzB,IAAA,IAAI,IAAI,CAAC,QAAQ,EAAE;AAClB,KAAA,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAA;AACrC,KAAA;AACA,IAAA,IAAI,IAAI,CAAC,MAAM,EAAE;AAChB,KAAA,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAA;AACjC,KAAA;AACA,IAAA,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,uBAAuB,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;AACnE,IAAA;GACA,IAAI,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE;AACrD,IAAA,OAAO,EAAC;AACT,IAAA;GACA,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;GAClH;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,QAAQ,EAAE;AACT,GAAA,SAAS,EAAE,IAAI;GACf,OAAO,CAAC,GAAG,EAAE;AACZ,IAAA,IAAI,GAAG,EAAE;AACR,KAAA,IAAI,CAAC,YAAY,GAAC;AACnB,KAAA;IACA;GACD;EACD;;AAED,CAAA,OAAO,EAAE;AACR;;;AAGC;AACA;;;AAGD,EAAA,MAAM,YAAY,GAAG;AACpB,GAAA,MAAM,MAAM,IAAI,CAAC,SAAO;AACxB,GAAA,IAAI,CAAC,GAAG,EAAE;IACT,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,OAAM,GAAI,KAAG;AAClB,GAAA,IAAI,CAAC,MAAO,GAAE,MAAI;AAClB,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AACxE,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;KAChB,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;AACjC,KAAA,MAAM,IAAG,GAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAK,IAAG,KAAG;AAC7C,KAAA,MAAM,GAAE,GAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAA,GAAI,IAAG,GAAI,GAAC;AAC1C,KAAA,MAAM,OAAM,GAAI,MAAM,IAAI,CAAC,mBAAmB,GAAC;KAC/C,IAAI,CAAC,OAAM,GAAI,OAAO,CAAC,MAAK,GAAI,CAAA;QAC7B,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAA;AACjE,QAAE,IAAE;KACJ,MAAK;AACN,KAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AAChB,KAAA,IAAI,CAAC,MAAK,GAAI,IAAI,CAAC,SAAQ,KAAM,KAAG;AACrC,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;IACA,OAAO,CAAC,KAAK,CAAC,gDAAgD,EAAE,GAAG,EAAA;AACnE,IAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AAChB,IAAA,IAAI,CAAC,MAAK,GAAI,IAAI,CAAC,SAAQ,KAAM,KAAG;AACrC,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,OAAQ,GAAE,MAAI;AACpB,IAAA;GACA;;AAED;;;;AAIC;AACA;AACA;;EAED,MAAM,mBAAmB,GAAG;GAC3B,IAAI,IAAI,CAAC,KAAM,KAAI,QAAO,IAAK,IAAI,CAAC,SAAQ,KAAM,IAAK,IAAG,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE;AAChH,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,MAAM,KAAI,GAAI,IAAI,CAAC,cAAc,CAAC,MAAK,GAAI,CAAE,GAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE,CAAE,GAAE,IAAI,CAAC,WAAS;GACnG,MAAM,OAAO,OAAO,GAAG,KAAK;AAC3B,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AACxE,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AACjB,KAAA,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;AACxC,KAAA;IACA,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;AACjC,IAAA,MAAM,IAAG,GAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAK,IAAG,KAAG;AAC7C,IAAA,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAE,GAAE,IAAG,GAAI,EAAC;AACtC,KAAA;GACA,MAAM,SAAU,GAAE,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,cAAa;KACpD,MAAM,CAAC,CAAC,MAAM,KAAK,MAAK,IAAK,MAAM,CAAC,QAAS,IAAG,MAAM,CAAC,MAAM,CAAA;AAC9D,KAAC,GAAG,CAAC,OAAO,MAAM,KAAK;AACtB,KAAA,IAAI;AACH,MAAA,MAAM,MAAK,GAAI,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAE,GAAE,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAE,GAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,eAAe,EAAE,MAAO,EAAC,GAAG,EAAA;MAC/J,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAA,IAAK,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAO,IAAG,EAAE,CAAC,EAAE;AAC/D,OAAA,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAM,KAAI,WAAY,GAAE,IAAI,CAAC,QAAS,GAAE,MAAM,CAAC,KAAK,CAAC,EAAA;AACtE,OAAA;MACA,MAAM,OAAM,GAAI,MAAM,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAA;MAC7G,MAAM,GAAE,GAAI,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,EAAE,EAAC,IAAK,MAAM,GAAG,OAAO,CAAC,EAAE,EAAG,IAAG,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,EAAA;AACvG,MAAA,MAAM,MAAK,GAAI,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,EAAA;AACvK,MAAA,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,MAAM,CAAC,MAAK,EAAG,CAAC,CAAA;AAC1F,MAAA,CAAE,MAAM;AACP,MAAA,OAAO,EAAC;AACT,MAAA;AACD,KAAC,CAAC,EAAA;AACH,GAAA,OAAO,SAAS,CAAC,IAAI,EAAC;GACtB;;AAED;;AAEC;AACA;;;;AAID,EAAA,YAAY,CAAC,KAAK,EAAE;GACnB,MAAM,KAAI,GAAI,IAAI,CAAC,cAAc,CAAC,KAAK,CAAE,IAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAA;AAC/D,GAAA,IAAI,KAAI,KAAM,IAAI,EAAE;IACnB,OAAO,KAAI;AACV,MAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;AACzC,MAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,cAAc,EAAE,CAAA;AAC1C,MAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;MAC/E,OAAO,CAAC,wBAAwB,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK;MACnD,MAAM,KAAI,GAAI,IAAI,CAAC,MAAO,GAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAA,GAAI,UAAQ;AAClE,MAAA,OAAO,UAAU,IAAG,IAAK,KAAI,KAAM,SAAU,IAAG,OAAO,KAAI,KAAM,WAAW,EAAG,GAAE,MAAM,CAAC,KAAK,CAAA;MAC7F,CAAA;AACH,IAAA;GACA,MAAM,MAAK,GAAI,KAAK,CAAC,MAAO,IAAG,KAAK,CAAC,KAAI,IAAK,IAAI,CAAC,YAAU;GAC7D,OAAO,KAAK,CAAC,UAAS,GAAI,CAAC,EAAE,MAAM,CAAE,EAAC,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAE,GAAE,MAAK;GACnE;;AAED;;;AAGC;;AAEA;AACA;AACA;;EAED,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE;AACxB,GAAA,MAAM,OAAM,GAAI,KAAI,IAAK,OAAO,KAAK,CAAC,YAAY,YAAY,KAAK,CAAC,OAAQ,KAAI,OAAO,KAAK,CAAC,OAAM,GAAI,GAAC;AACxG,GAAA,MAAM,KAAI,GAAI,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,EAAA;GACrC,IAAI,KAAI,KAAM,QAAQ,KAAM,KAAI,SAAQ,IAAK,OAAO,KAAM,KAAI,QAAQ,EAAE;AACvE,IAAA,OAAO,EAAC;AACT,IAAA;GACA,MAAM,KAAM,GAAE,IAAI,CAAC,WAAU,IAAK,IAAI,CAAC,WAAW,CAAC,GAAG,EAAA;AACtD,GAAA,OAAO,KAAI,IAAK,OAAO,KAAK,CAAC,KAAK,CAAA,KAAM,QAAO,GAAI,KAAK,CAAC,KAAK,CAAA,GAAI,MAAM,CAAC,KAAK,CAAA;GAC9E;;AAED;;;AAGC;;;;AAID,EAAA,cAAc,CAAC,KAAK,EAAE;AACrB,GAAA,MAAM,OAAM,GAAI,KAAI,IAAK,OAAO,KAAK,CAAC,YAAY,YAAY,KAAK,CAAC,OAAQ,KAAI,OAAO,KAAK,CAAC,OAAM,GAAI,GAAC;AACxG,GAAA,MAAM,MAAK,GAAI,KAAK,CAAC,MAAO,IAAG,KAAK,CAAC,KAAM,IAAG,GAAC;AAC/C,GAAA,KAAK,MAAM,IAAG,IAAK,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAA,GAAI,IAAI,CAAC,YAAW,GAAI,EAAE,EAAE;IAC7E,IAAI,CAAC,IAAG,IAAK,OAAO,IAAI,CAAC,KAAM,KAAI,QAAS,IAAG,IAAI,CAAC,KAAM,KAAI,EAAC,IAAK,OAAO,IAAI,CAAC,KAAM,KAAI,QAAS,IAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE;AAC1I,KAAA,QAAO;AACR,KAAA;AACA,IAAA,IAAI,IAAI,CAAC,MAAO,IAAG,IAAI,CAAC,MAAO,KAAI,MAAM,EAAE;AAC1C,KAAA,QAAO;AACR,KAAA;AACA,IAAA,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;AAC7F,KAAA,QAAO;AACR,KAAA;AACA,IAAA,OAAO,IAAI,CAAC,KAAI;AACjB,IAAA;AACA,GAAA,OAAO,IAAG;GACV;;AAED;;;AAGC;;;;;AAKD,EAAA,QAAQ,CAAC,KAAK,EAAE;GACf,MAAM,MAAO,GAAE,IAAI,CAAC,aAAW;AAC/B,GAAA,MAAM,SAAS,KAAK,CAAC,MAAK,IAAK,KAAK,CAAC,MAAI;AACzC,GAAA,IAAI,CAAC,MAAK,IAAK,CAAC,MAAM,EAAE;AACvB,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,MAAM,KAAM,GAAE,KAAK,CAAC,UAAS,IAAK,GAAC;GACnC,MAAM,MAAO,GAAE,KAAK,CAAC,SAAU,GAAE,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAE,GAAE,GAAC;GAC1D,MAAM,KAAM,GAAE,CAAC,UAAU,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAE,IAAG,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS;AAC1G,OAAG,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAE,IAAG,MAAM,CAAC,MAAM,EAAA;GACjD,OAAO,OAAO,KAAM,KAAI,QAAO,IAAK,KAAM,KAAI,EAAG,GAAE,KAAM,GAAE,IAAG;GAC9D;;AAED;;;;AAIA,EAAA,SAAS,CAAC,KAAK,EAAE;GAChB,IAAI,KAAK,CAAC,gBAAgB,EAAE;IAC3B,OAAO,KAAK,CAAC,gBAAe;AAC7B,IAAA;GACA,MAAM,EAAG,GAAE,KAAK,CAAC,KAAM,IAAG,KAAK,CAAC,MAAK,IAAK,KAAK,CAAC,IAAG,IAAK,GAAC;;GAEzD,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,aAAY,IAAK,KAAK,CAAC,aAAc,KAAI,MAAM,CAAA,IAAK,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,EAAC;GAC3G;;AAED;;;AAGC;;;AAGA;;AAED,EAAA,WAAW,CAAC,KAAK,EAAE;AAClB,GAAA,MAAM,GAAI,GAAE,KAAK,CAAC,gBAAe,IAAK,KAAK,CAAC,OAAQ,IAAG,KAAK,CAAC,UAAQ;AACrE,GAAA,MAAM,IAAG,GAAI,GAAE,GAAI,IAAI,IAAI,CAAC,GAAG,CAAE,GAAE,KAAG;GACtC,MAAM,OAAO,IAAG,IAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAA,GAAI,CAAC,EAAE,eAAe,CAAC,IAAI,CAAC,CAAE,CAAA,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,CAAE,GAAE,GAAC;AAC5G,GAAA,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAK,KAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAA;GAC/E;;AAED;;AAEC;AACA;;;;AAID,EAAA,WAAW,CAAC,KAAK,EAAE;GAClB,MAAM,KAAM,GAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAE,IAAG,EAAE,EAAE,QAAQ,CAAC,SAAS,EAAA;AAC7D,GAAA,MAAM,KAAI,GAAI,CAAC,KAAM,GAAE,EAAG,GAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAA;GACjD,IAAI,KAAK,CAAC,aAAY,IAAK,KAAK,CAAC,aAAY,KAAM,MAAM,EAAE;AAC1D,IAAA,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EAAA;AACtC,IAAA;AACA,GAAA,IAAI,KAAK,CAAC,UAAU,EAAE;AACrB,IAAA,KAAK,CAAC,IAAI,CAACA,SAAC,CAAC,eAAe,EAAE,qBAAqB,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,UAAS,EAAG,CAAC,EAAA;AACjF,IAAA;AACA,GAAA,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAG,KAAM,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAA;GACnD;;AAED,EAAA,UAAU,CAAC,KAAK,EAAE;AACjB,GAAA,MAAM,GAAI,GAAE,KAAK,CAAC,gBAAe,IAAK,KAAK,CAAC,OAAQ,IAAG,KAAK,CAAC,UAAQ;AACrE,GAAA,IAAI,GAAI,KAAI,SAAU,IAAG,GAAE,KAAM,IAAI,EAAE;AACtC,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,MAAM,CAAA,GAAI,IAAI,IAAI,CAAC,GAAG,EAAA;AACtB,GAAA,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAE,KAAI,IAAI,EAAE;AACvC,IAAA,OAAO,MAAM,CAAC,GAAG,CAAA;AAClB,IAAA;AACA,GAAA,OAAO,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,CAAA;GACpC;EACD;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"CnAuditTrailCard.vue2.js","sources":["../../../../src/components/CnAuditTrailCard/CnAuditTrailCard.vue"],"sourcesContent":["<!--\n CnAuditTrailCard — compact audit-trail widget for the integration\n registry.\n\n Surface-aware shell around the `audit-trail` integration: fetches\n the object's recent audit-trail entries (query-time storage strategy\n per AD-22) and renders them in a CnDetailCard.\n\n Per umbrella change `pluggable-integration-registry` AD-19 (surface\n fallback), one component handles all surfaces — `surface` is\n forwarded so the component can branch internally if desired.\n-->\n<template>\n\t<CnDetailCard\n\t\t:title=\"resolvedTitle\"\n\t\t:icon=\"History\"\n\t\t:collapsible=\"collapsible\"\n\t\t:data-surface=\"surface\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<p v-else-if=\"failed\"\n\t\t\tclass=\"cn-audit-card__empty\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-audit-card-failed\">\n\t\t\t{{ failedLabel }}\n\t\t</p>\n\t\t<div v-else-if=\"shownEntries.length === 0\" class=\"cn-audit-card__empty\">\n\t\t\t{{ noEntriesLabel }}\n\t\t</div>\n\t\t<ul v-else class=\"cn-audit-card__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"entry in displayedEntries\"\n\t\t\t\t:key=\"entry.id\"\n\t\t\t\tclass=\"cn-audit-card__row\"\n\t\t\t\t:class=\"{ 'cn-audit-card__row--stacked': layout === 'stacked' }\">\n\t\t\t\t<div class=\"cn-audit-card__row-head\">\n\t\t\t\t\t<strong class=\"cn-audit-card__action\">{{ formatAction(entry) }}</strong>\n\t\t\t\t\t<span v-if=\"layout !== 'stacked'\" class=\"cn-audit-card__when\">{{ formatWhen(entry) }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-audit-card__row-body\">\n\t\t\t\t\t<span v-if=\"layout === 'stacked'\" class=\"cn-audit-card__when\" data-testid=\"cn-audit-card-when-below\">{{ stackedLine(entry) }}</span>\n\t\t\t\t\t<span v-else class=\"cn-audit-card__actor\">{{ formatActor(entry) }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"entry.authorized === false\"\n\t\t\t\t\t\tclass=\"cn-audit-card__refused\"\n\t\t\t\t\t\tdata-testid=\"cn-audit-card-refused\">{{ refusedLabel }}</span>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"entry.reason\" class=\"cn-audit-card__reason\">\n\t\t\t\t\t{{ entry.reason }}\n\t\t\t\t</p>\n\t\t\t</li>\n\t\t</ul>\n\t\t<p v-if=\"footnote\" class=\"cn-audit-card__footnote\" data-testid=\"cn-audit-trail-widget-footnote\">\n\t\t\t{{ footnote }}\n\t\t</p>\n\t\t<template v-if=\"shownEntries.length > maxDisplay\" #footer>\n\t\t\t<button class=\"cn-audit-card__show-all\" @click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ shownEntries.length }})\n\t\t\t</button>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport History from 'vue-material-design-icons/History.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport { formatBoardDate, formatTimeOfDay } from '../../utils/boardDate.js'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { leafSourceUrl } from '../../utils/leafSourceUrl.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { userDisplayName } from '../../utils/userDisplayName.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * A changed value as an entry records it: OpenRegister writes `{ old, new }`,\n * other sources the value itself.\n *\n * @param {unknown} value The recorded change.\n * @return {unknown} The value it changed to.\n */\nfunction newValueOf(value) {\n\treturn value !== null && typeof value === 'object' && Object.hasOwn(value, 'new') ? value.new : value\n}\n\n/**\n * @param {object} entry An audit entry.\n * @return {number} When it happened, in ms; 0 when unreadable.\n */\nfunction entryTime(entry) {\n\tconst time = new Date(entry.creationDateTime || entry.created || entry.timestamp || 0).getTime()\n\treturn Number.isNaN(time) ? 0 : time\n}\n\n/**\n * CnAuditTrailCard — compact audit-trail widget rendered by the\n * integration registry on dashboard and detail surfaces.\n *\n * Basic usage\n * ```vue\n * <CnAuditTrailCard\n * :register=\"registerId\"\n * :schema=\"schemaId\"\n * :object-id=\"objectId\"\n * surface=\"detail-page\" />\n * ```\n */\nexport default {\n\tname: 'CnAuditTrailCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon },\n\n\tprops: {\n\t\t/**\n\t\t * A muted line under the trail, inside the card (\"Kenmerk ZT-OMV-REG\").\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-footnote/specs/audit-trail/spec.md#requirement-a-history-card-can-end-in-a-line-about-the-record\n\t\t */\n\t\tfootnote: { type: String, default: '' },\n\t\t/** OpenRegister register id (slug or uuid). Optional for `scope: \"app\"`. */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). Optional for `scope: \"app\"`. */\n\t\tschema: { type: String, default: '' },\n\t\t/** Parent object id. Required for `scope: \"object\"` (the default); unused for `scope: \"app\"`. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/**\n\t\t * What the card lists. `object` (the default) is one object's trail\n\t\t * and needs `register`, `schema` and `objectId`. `app` is the\n\t\t * app-wide feed: the entries of every object the caller may read\n\t\t * (OpenRegister's `/audit-trails/readable`), narrowed to `register`\n\t\t * and `schema` when those are set.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t */\n\t\tscope: {\n\t\t\ttype: String,\n\t\t\tdefault: 'object',\n\t\t\tvalidator: (value) => ['object', 'app'].includes(value),\n\t\t},\n\n\t\t/** Rendering surface — passed for AD-19 surface fallback consumers. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (value) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(value),\n\t\t},\n\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\n\t\t/**\n\t\t * Read the trail of something that is not an OpenRegister object:\n\t\t * `{ kind: 'flow-task', id }` reads `${apiBase}/flow-tasks/{id}/audit`,\n\t\t * oldest first. `id` may be left out or written `@objectId`.\n\t\t *\n\t\t * @type {{kind: string, id?: (string|number)}|null}\n\t\t */\n\t\tsource: { type: Object, default: null },\n\n\t\t/** A trail URL that replaces the object's own; `{id}` is filled with the source's id or `objectId`. */\n\t\tendpoint: { type: String, default: '' },\n\n\t\t/** `newest` first (the object trail's order) or `oldest` first; empty takes `oldest` for a source and `newest` otherwise. */\n\t\torder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t\tvalidator: (value) => ['', 'newest', 'oldest'].includes(value),\n\t\t},\n\n\t\t/** Maximum rows to render. */\n\t\tmaxDisplay: { type: Number, default: 5 },\n\t\t/**\n\t\t * `stacked` (DqTaak \"Historie\"): the action, then one muted line under\n\t\t * it with the moment (\"6 okt 09:05\") and who, when the action does not\n\t\t * already name them. Default: the moment beside the action, who under it.\n\t\t */\n\t\tlayout: { type: String, default: '' },\n\t\t/**\n\t\t * Actions the card leaves out (case-insensitive), such as `['read']`\n\t\t * for a history of what changed. It then reads more entries than it\n\t\t * shows, so the rows it leaves out do not crowd the rest away.\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-exclude-actions/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-events-by-action\n\t\t */\n\t\texcludeActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * Actors the card leaves out by user id (case-insensitive), such as\n\t\t * `['System']` for a history of what people did: the bookkeeping a\n\t\t * background job writes is not shown.\n\t\t *\n\t\t * @spec openspec/changes/audit-card-exclude-actors/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-entries-by-actor\n\t\t */\n\t\texcludeActors: { type: Array, default: () => [] },\n\t\t/** Whether the card collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Pre-translated empty label. */\n\t\tnoEntriesLabel: { type: String, default: () => t('nextcloud-vue', 'No audit entries yet') },\n\t\t/** Pre-translated overflow label. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/** Pre-translated fallback action label. */\n\t\tactionLabel: { type: String, default: () => t('nextcloud-vue', 'Change') },\n\t\t/** Shown on an entry the server refused (`authorized: false`). */\n\t\trefusedLabel: { type: String, default: () => t('nextcloud-vue', '(refused)') },\n\t\t/**\n\t\t * What happened, in words, by action (`claim`) or by action and the\n\t\t * state it led to (`complete:completed`, tried first). `{actor}`,\n\t\t * `{state}` and `{changed.<key>}` (a value the entry recorded, a dotted key\n\t\t * reading into it such as `{changed.data.fileName}`, in the\n\t\t * words of `valueLabels`) are filled in; a label that names the actor leaves it off\n\t\t * the line under it. An action without a label shows as written.\n\t\t *\n\t\t * @type {Object<string, string>|null}\n\t\t */\n\t\tactionLabels: { type: Object, default: null },\n\t\t/**\n\t\t * Words for the values an action label quotes as `{changed.<key>}`:\n\t\t * `{ purpose: { handling: 'Handling' } }`. A value without an entry\n\t\t * shows as written.\n\t\t *\n\t\t * @type {{[key: string]: {[value: string]: string}}|null}\n\t\t */\n\t\tvalueLabels: { type: Object, default: null },\n\t\t/**\n\t\t * What happened, in words, by the field an entry changed: rules\n\t\t * `[{ action?, field, to?, label }]`, the first whose `field` the entry\n\t\t * changed (to `to`, when given) wins over `actionLabels`. A label fills\n\t\t * the same tokens, plus `{object.<path>}` from `object`\n\t\t * (\"Version {object.version} published\" for `isDraft` set to false).\n\t\t *\n\t\t * @type {Array<{action?: string, field: string, to?: unknown, label: string}>}\n\t\t */\n\t\tchangeLabels: { type: Array, default: () => [] },\n\t\t/** The audited record, for `{object.<path>}` in a label; null without one. */\n\t\tobject: { type: Object, default: null },\n\t\t/**\n\t\t * Records beside the object whose events belong in its history:\n\t\t * `[{ as, register, schema, filter, limit? }]`. The card lists the\n\t\t * objects matching `filter` (`@objectId` is this object; at most\n\t\t * `limit`, default 5), reads their trails and merges the entries with\n\t\t * the object's own, newest first. A related entry is labelled by\n\t\t * `actionLabels[\"<as>.<action>\"]` first. Object scope only.\n\t\t *\n\t\t * @type {Array<{as: string, register: string, schema: string, filter?: object, limit?: number}>}\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\trelatedSources: { type: Array, default: () => [] },\n\t\t/** Shown when a `source` or `endpoint` read failed. */\n\t\tfailedLabel: { type: String, default: () => t('nextcloud-vue', 'The history could not be loaded') },\n\t},\n\n\temits: ['show-all'],\n\n\tdata() {\n\t\treturn {\n\t\t\tHistory: markRaw(History),\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\t/** A `source` or `endpoint` read failed: said, rather than shown as an empty trail. */\n\t\t\tfailed: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Audit trail')\n\t\t},\n\n\t\t/** @return {Array<object>} The entries without the excluded actions. */\n\t\tshownEntries() {\n\t\t\tconst excluded = this.excludeActions.map((action) => String(action).toLowerCase())\n\t\t\tconst actors = this.excludeActors.map((actor) => String(actor).toLowerCase())\n\t\t\tif (excluded.length === 0 && actors.length === 0) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.filter((entry) => !excluded.includes(String(entry.action || entry.event || '').toLowerCase())\n\t\t\t\t&& !actors.includes(String(entry.user || '').toLowerCase()))\n\t\t},\n\n\t\t/** @return {boolean} Whether the card leaves entries out, and so reads more than it shows. */\n\t\tfiltersEntries() {\n\t\t\treturn this.excludeActions.length > 0 || this.excludeActors.length > 0\n\t\t},\n\n\t\tdisplayedEntries() {\n\t\t\tconst entries = this.oldestFirst ? [...this.shownEntries].sort((a, b) => entryTime(a) - entryTime(b)) : this.shownEntries\n\t\t\treturn entries.slice(0, this.maxDisplay)\n\t\t},\n\n\t\t/**\n\t\t * The trail URL a `source` or `endpoint` names, '' while its record id\n\t\t * is unknown, or null when the card reads an object.\n\t\t *\n\t\t * @return {string|null}\n\t\t * @spec openspec/changes/leaf-cards-read-a-source/specs/leaf-cards-read-a-source/spec.md#requirement-a-leaf-card-reads-a-source-or-an-endpoint\n\t\t */\n\t\tsourceUrl() {\n\t\t\treturn leafSourceUrl({ source: this.source, endpoint: this.endpoint, apiBase: this.apiBase, objectId: this.objectId }, 'audit')\n\t\t},\n\n\t\t/** @return {boolean} Whether the entries read oldest first. */\n\t\toldestFirst() {\n\t\t\treturn this.order === 'oldest' || (this.order === '' && this.sourceUrl !== null)\n\t\t},\n\n\t\t/**\n\t\t * The path the card reads (prefixed at fetch time), or '' when it has nothing to read: the\n\t\t * object's own trail, or the app-wide readable feed narrowed to the\n\t\t * register and schema when set.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {string}\n\t\t */\n\t\tfetchUrl() {\n\t\t\tif (this.sourceUrl !== null) {\n\t\t\t\treturn this.sourceUrl\n\t\t\t}\n\t\t\tconst limit = this.filtersEntries ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay\n\t\t\tconst params = new URLSearchParams({ limit: String(limit) })\n\t\t\tif (this.scope === 'app') {\n\t\t\t\tif (this.register) {\n\t\t\t\t\tparams.set('register', this.register)\n\t\t\t\t}\n\t\t\t\tif (this.schema) {\n\t\t\t\t\tparams.set('schema', this.schema)\n\t\t\t\t}\n\t\t\t\treturn `${this.apiBase}/audit-trails/readable?${params.toString()}`\n\t\t\t}\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails?${params.toString()}`\n\t\t},\n\t},\n\n\twatch: {\n\t\tfetchUrl: {\n\t\t\timmediate: true,\n\t\t\thandler(url) {\n\t\t\t\tif (url) {\n\t\t\t\t\tthis.fetchEntries()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the entries from `fetchUrl`. The readable feed answers\n\t\t * `{ rows, nextCursor }`, the object trail `{ results }`.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchEntries() {\n\t\t\tconst url = this.fetchUrl\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst list = data.results || data.rows || data\n\t\t\t\t\tconst own = Array.isArray(list) ? list : []\n\t\t\t\t\tconst related = await this.fetchRelatedEntries()\n\t\t\t\t\tthis.entries = related.length > 0\n\t\t\t\t\t\t? [...own, ...related].sort((a, b) => entryTime(b) - entryTime(a))\n\t\t\t\t\t\t: own\n\t\t\t\t} else {\n\t\t\t\t\tthis.entries = []\n\t\t\t\t\tthis.failed = this.sourceUrl !== null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnAuditTrailCard] failed to fetch audit trail', err)\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.failed = this.sourceUrl !== null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The entries of the records beside the object (`relatedSources`),\n\t\t * each tagged with its source's `as`. A read that fails leaves that\n\t\t * source out.\n\t\t *\n\t\t * @return {Promise<Array<object>>} The entries.\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\tasync fetchRelatedEntries() {\n\t\t\tif (this.scope !== 'object' || this.sourceUrl !== null || !this.objectId || !Array.isArray(this.relatedSources)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst limit = this.filtersEntries ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay\n\t\t\tconst read = async (url) => {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(String(response.status))\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = data.results || data.rows || data\n\t\t\t\treturn Array.isArray(list) ? list : []\n\t\t\t}\n\t\t\tconst perSource = await Promise.all(this.relatedSources\n\t\t\t\t.filter((source) => source && source.register && source.schema)\n\t\t\t\t.map(async (source) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst params = new URLSearchParams({ _limit: String(Number(source.limit) > 0 ? Number(source.limit) : 5), _order: JSON.stringify({ '@self.created': 'DESC' }) })\n\t\t\t\t\t\tfor (const [key, value] of Object.entries(source.filter || {})) {\n\t\t\t\t\t\t\tparams.set(key, value === '@objectId' ? this.objectId : String(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst objects = await read(`${this.apiBase}/objects/${source.register}/${source.schema}?${params.toString()}`)\n\t\t\t\t\t\tconst ids = objects.map((object) => object?.id || object?.['@self']?.id || object?.uuid).filter(Boolean)\n\t\t\t\t\t\tconst trails = await Promise.all(ids.map((id) => read(`${this.apiBase}/objects/${source.register}/${source.schema}/${id}/audit-trails?limit=${limit}`).catch(() => [])))\n\t\t\t\t\t\treturn trails.flat().map((entry) => ({ ...entry, relatedAs: source.as || source.schema }))\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn []\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\treturn perSource.flat()\n\t\t},\n\n\t\t/**\n\t\t * What happened: the action, with the state it led to when the entry\n\t\t * names one (a flow task's `stateAfter`).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t */\n\t\tformatAction(entry) {\n\t\t\tconst label = this.changeLabelFor(entry) ?? this.labelFor(entry)\n\t\t\tif (label !== null) {\n\t\t\t\treturn label\n\t\t\t\t\t.replace('{actor}', this.actorName(entry))\n\t\t\t\t\t.replace('{state}', entry.stateAfter || '')\n\t\t\t\t\t.replace(/\\{changed\\.([\\w.-]+)\\}/g, (match, key) => this.changedValue(entry, key))\n\t\t\t\t\t.replace(/\\{object\\.([\\w.-]+)\\}/g, (match, path) => {\n\t\t\t\t\t\tconst value = this.object ? readPath(this.object, path) : undefined\n\t\t\t\t\t\treturn value === null || value === undefined || typeof value === 'object' ? '' : String(value)\n\t\t\t\t\t})\n\t\t\t}\n\t\t\tconst action = entry.action || entry.event || this.actionLabel\n\t\t\treturn entry.stateAfter ? `${action} (${entry.stateAfter})` : action\n\t\t},\n\n\t\t/**\n\t\t * A value the entry recorded under `changed` (an audit entry's context),\n\t\t * in the words of `valueLabels`; '' when it recorded none.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {string} key The recorded key.\n\t\t * @return {string} The value in words.\n\t\t * @spec openspec/changes/audit-label-changed-values/specs/audit-trail/spec.md#requirement-a-trail-label-can-quote-what-the-entry-recorded\n\t\t */\n\t\tchangedValue(entry, key) {\n\t\t\tconst changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {}\n\t\t\t// A dotted key reads into what the entry recorded (`data.fileName` on a file action).\n\t\t\tconst value = String(key).split('.').reduce((at, part) => newValueOf(at !== null && typeof at === 'object' ? at[part] : undefined), changed)\n\t\t\tif (value === null || value === undefined || typeof value === 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst words = this.valueLabels && this.valueLabels[key]\n\t\t\treturn words && typeof words[value] === 'string' ? words[value] : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The `changeLabels` rule an entry matches: the first whose field the\n\t\t * entry changed, for its action and to its value when the rule names them.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string|null} The label, or null when no rule matches.\n\t\t */\n\t\tchangeLabelFor(entry) {\n\t\t\tconst changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {}\n\t\t\tconst action = entry.action || entry.event || ''\n\t\t\tfor (const rule of Array.isArray(this.changeLabels) ? this.changeLabels : []) {\n\t\t\t\tif (!rule || typeof rule.label !== 'string' || rule.label === '' || typeof rule.field !== 'string' || !Object.hasOwn(changed, rule.field)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (rule.action && rule.action !== action) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (Object.hasOwn(rule, 'to') && String(newValueOf(changed[rule.field])) !== String(rule.to)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn rule.label\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The `actionLabels` entry for an entry: by action and state first,\n\t\t * then by action.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string|null} The label, or null when none is declared.\n\t\t * @spec openspec/changes/audit-trail-action-labels/specs/audit-trail/spec.md#requirement-a-trail-can-say-what-happened-in-words\n\t\t */\n\t\tlabelFor(entry) {\n\t\t\tconst labels = this.actionLabels\n\t\t\tconst action = entry.action || entry.event\n\t\t\tif (!labels || !action) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst state = entry.stateAfter || ''\n\t\t\tconst prefix = entry.relatedAs ? `${entry.relatedAs}.` : ''\n\t\t\tconst label = (prefix ? (labels[`${prefix}${action}:${state}`] ?? labels[`${prefix}${action}`]) : undefined)\n\t\t\t\t?? labels[`${action}:${state}`] ?? labels[action]\n\t\t\treturn typeof label === 'string' && label !== '' ? label : null\n\t\t},\n\n\t\t/**\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} Who did it, by name where the entry carries one.\n\t\t */\n\t\tactorName(entry) {\n\t\t\tif (entry.actorDisplayName) {\n\t\t\t\treturn entry.actorDisplayName\n\t\t\t}\n\t\t\tconst id = entry.actor || entry.userId || entry.user || ''\n\t\t\t// A person's user id reads as their display name once it is known.\n\t\t\treturn (id && (!entry.performerType || entry.performerType === 'user') && userDisplayName(String(id))) || id\n\t\t},\n\n\t\t/**\n\t\t * The muted line of a stacked row: the moment in the board's short\n\t\t * form (\"6 okt 09:05\") and who, unless the action names them already.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t * @spec openspec/changes/audit-card-stacked-rows/specs/audit-trail/spec.md#requirement-an-audit-row-can-put-its-moment-under-the-action\n\t\t */\n\t\tstackedLine(entry) {\n\t\t\tconst raw = entry.creationDateTime || entry.created || entry.timestamp\n\t\t\tconst date = raw ? new Date(raw) : null\n\t\t\tconst when = date && !Number.isNaN(date.getTime()) ? `${formatBoardDate(date)} ${formatTimeOfDay(date)}` : ''\n\t\t\treturn [when, this.formatActor(entry)].filter((part) => part !== '').join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * Who did it: the actor, the kind of performer when it is not a\n\t\t * person (a flow, the system), and on whose behalf.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t */\n\t\tformatActor(entry) {\n\t\t\tconst named = (this.labelFor(entry) || '').includes('{actor}')\n\t\t\tconst parts = [named ? '' : this.actorName(entry)]\n\t\t\tif (entry.performerType && entry.performerType !== 'user') {\n\t\t\t\tparts.push(`(${entry.performerType})`)\n\t\t\t}\n\t\t\tif (entry.onBehalfOf) {\n\t\t\t\tparts.push(t('nextcloud-vue', 'on behalf of {name}', { name: entry.onBehalfOf }))\n\t\t\t}\n\t\t\treturn parts.filter((part) => part !== '').join(' ')\n\t\t},\n\n\t\tformatWhen(entry) {\n\t\t\tconst raw = entry.creationDateTime || entry.created || entry.timestamp\n\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst d = new Date(raw)\n\t\t\tif (Number.isNaN(d.getTime()) === true) {\n\t\t\t\treturn String(raw)\n\t\t\t}\n\t\t\treturn d.toLocaleString(userLocale())\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-audit-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-audit-card__row {\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-audit-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-audit-card__row-head {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-audit-card__action {\n\tcolor: var(--color-main-text);\n}\n\n.cn-audit-card__when {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\twhite-space: nowrap;\n}\n\n.cn-audit-card__row-body {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-audit-card__refused {\n\tmargin-inline-start: 6px;\n\tfont-weight: 700;\n\tcolor: var(--color-error-text, var(--color-main-text));\n}\n\n.cn-audit-card__reason {\n\tmargin: 2px 0 0;\n\tfont-size: 0.9em;\n\toverflow-wrap: anywhere;\n}\n\n.cn-audit-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n\n.cn-audit-card__footnote {\n\tmargin: 12px 0 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-audit-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tcursor: pointer;\n\tpadding: 4px 0;\n\tfont: inherit;\n}\n\n.cn-audit-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDetailCard","t"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAuditTrailCard.vue3.js","sources":["../../../../src/components/CnAuditTrailCard/CnAuditTrailCard.vue?vue&type=template&id=7e58faa4&lang.js"],"sourcesContent":["<!--\n CnAuditTrailCard — compact audit-trail widget for the integration\n registry.\n\n Surface-aware shell around the `audit-trail` integration: fetches\n the object's recent audit-trail entries (query-time storage strategy\n per AD-22) and renders them in a CnDetailCard.\n\n Per umbrella change `pluggable-integration-registry` AD-19 (surface\n fallback), one component handles all surfaces — `surface` is\n forwarded so the component can branch internally if desired.\n-->\n<template>\n\t<CnDetailCard\n\t\t:title=\"resolvedTitle\"\n\t\t:icon=\"History\"\n\t\t:collapsible=\"collapsible\"\n\t\t:data-surface=\"surface\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<p v-else-if=\"failed\"\n\t\t\tclass=\"cn-audit-card__empty\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-audit-card-failed\">\n\t\t\t{{ failedLabel }}\n\t\t</p>\n\t\t<div v-else-if=\"shownEntries.length === 0\" class=\"cn-audit-card__empty\">\n\t\t\t{{ noEntriesLabel }}\n\t\t</div>\n\t\t<ul v-else class=\"cn-audit-card__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"entry in displayedEntries\"\n\t\t\t\t:key=\"entry.id\"\n\t\t\t\tclass=\"cn-audit-card__row\"\n\t\t\t\t:class=\"{ 'cn-audit-card__row--stacked': layout === 'stacked' }\">\n\t\t\t\t<div class=\"cn-audit-card__row-head\">\n\t\t\t\t\t<strong class=\"cn-audit-card__action\">{{ formatAction(entry) }}</strong>\n\t\t\t\t\t<span v-if=\"layout !== 'stacked'\" class=\"cn-audit-card__when\">{{ formatWhen(entry) }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-audit-card__row-body\">\n\t\t\t\t\t<span v-if=\"layout === 'stacked'\" class=\"cn-audit-card__when\" data-testid=\"cn-audit-card-when-below\">{{ stackedLine(entry) }}</span>\n\t\t\t\t\t<span v-else class=\"cn-audit-card__actor\">{{ formatActor(entry) }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"entry.authorized === false\"\n\t\t\t\t\t\tclass=\"cn-audit-card__refused\"\n\t\t\t\t\t\tdata-testid=\"cn-audit-card-refused\">{{ refusedLabel }}</span>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"entry.reason\" class=\"cn-audit-card__reason\">\n\t\t\t\t\t{{ entry.reason }}\n\t\t\t\t</p>\n\t\t\t</li>\n\t\t</ul>\n\t\t<p v-if=\"footnote\" class=\"cn-audit-card__footnote\" data-testid=\"cn-audit-trail-widget-footnote\">\n\t\t\t{{ footnote }}\n\t\t</p>\n\t\t<template v-if=\"shownEntries.length > maxDisplay\" #footer>\n\t\t\t<button class=\"cn-audit-card__show-all\" @click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ shownEntries.length }})\n\t\t\t</button>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport History from 'vue-material-design-icons/History.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport { formatBoardDate, formatTimeOfDay } from '../../utils/boardDate.js'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { leafSourceUrl } from '../../utils/leafSourceUrl.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { userDisplayName } from '../../utils/userDisplayName.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * A changed value as an entry records it: OpenRegister writes `{ old, new }`,\n * other sources the value itself.\n *\n * @param {unknown} value The recorded change.\n * @return {unknown} The value it changed to.\n */\nfunction newValueOf(value) {\n\treturn value !== null && typeof value === 'object' && Object.hasOwn(value, 'new') ? value.new : value\n}\n\n/**\n * @param {object} entry An audit entry.\n * @return {number} When it happened, in ms; 0 when unreadable.\n */\nfunction entryTime(entry) {\n\tconst time = new Date(entry.creationDateTime || entry.created || entry.timestamp || 0).getTime()\n\treturn Number.isNaN(time) ? 0 : time\n}\n\n/**\n * CnAuditTrailCard — compact audit-trail widget rendered by the\n * integration registry on dashboard and detail surfaces.\n *\n * Basic usage\n * ```vue\n * <CnAuditTrailCard\n * :register=\"registerId\"\n * :schema=\"schemaId\"\n * :object-id=\"objectId\"\n * surface=\"detail-page\" />\n * ```\n */\nexport default {\n\tname: 'CnAuditTrailCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon },\n\n\tprops: {\n\t\t/**\n\t\t * A muted line under the trail, inside the card (\"Kenmerk ZT-OMV-REG\").\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-footnote/specs/audit-trail/spec.md#requirement-a-history-card-can-end-in-a-line-about-the-record\n\t\t */\n\t\tfootnote: { type: String, default: '' },\n\t\t/** OpenRegister register id (slug or uuid). Optional for `scope: \"app\"`. */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). Optional for `scope: \"app\"`. */\n\t\tschema: { type: String, default: '' },\n\t\t/** Parent object id. Required for `scope: \"object\"` (the default); unused for `scope: \"app\"`. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/**\n\t\t * What the card lists. `object` (the default) is one object's trail\n\t\t * and needs `register`, `schema` and `objectId`. `app` is the\n\t\t * app-wide feed: the entries of every object the caller may read\n\t\t * (OpenRegister's `/audit-trails/readable`), narrowed to `register`\n\t\t * and `schema` when those are set.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t */\n\t\tscope: {\n\t\t\ttype: String,\n\t\t\tdefault: 'object',\n\t\t\tvalidator: (value) => ['object', 'app'].includes(value),\n\t\t},\n\n\t\t/** Rendering surface — passed for AD-19 surface fallback consumers. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (value) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(value),\n\t\t},\n\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\n\t\t/**\n\t\t * Read the trail of something that is not an OpenRegister object:\n\t\t * `{ kind: 'flow-task', id }` reads `${apiBase}/flow-tasks/{id}/audit`,\n\t\t * oldest first. `id` may be left out or written `@objectId`.\n\t\t *\n\t\t * @type {{kind: string, id?: (string|number)}|null}\n\t\t */\n\t\tsource: { type: Object, default: null },\n\n\t\t/** A trail URL that replaces the object's own; `{id}` is filled with the source's id or `objectId`. */\n\t\tendpoint: { type: String, default: '' },\n\n\t\t/** `newest` first (the object trail's order) or `oldest` first; empty takes `oldest` for a source and `newest` otherwise. */\n\t\torder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t\tvalidator: (value) => ['', 'newest', 'oldest'].includes(value),\n\t\t},\n\n\t\t/** Maximum rows to render. */\n\t\tmaxDisplay: { type: Number, default: 5 },\n\t\t/**\n\t\t * `stacked` (DqTaak \"Historie\"): the action, then one muted line under\n\t\t * it with the moment (\"6 okt 09:05\") and who, when the action does not\n\t\t * already name them. Default: the moment beside the action, who under it.\n\t\t */\n\t\tlayout: { type: String, default: '' },\n\t\t/**\n\t\t * Actions the card leaves out (case-insensitive), such as `['read']`\n\t\t * for a history of what changed. It then reads more entries than it\n\t\t * shows, so the rows it leaves out do not crowd the rest away.\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-exclude-actions/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-events-by-action\n\t\t */\n\t\texcludeActions: { type: Array, default: () => [] },\n\t\t/** Whether the card collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Pre-translated empty label. */\n\t\tnoEntriesLabel: { type: String, default: () => t('nextcloud-vue', 'No audit entries yet') },\n\t\t/** Pre-translated overflow label. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/** Pre-translated fallback action label. */\n\t\tactionLabel: { type: String, default: () => t('nextcloud-vue', 'Change') },\n\t\t/** Shown on an entry the server refused (`authorized: false`). */\n\t\trefusedLabel: { type: String, default: () => t('nextcloud-vue', '(refused)') },\n\t\t/**\n\t\t * What happened, in words, by action (`claim`) or by action and the\n\t\t * state it led to (`complete:completed`, tried first). `{actor}`,\n\t\t * `{state}` and `{changed.<key>}` (a value the entry recorded, in the\n\t\t * words of `valueLabels`) are filled in; a label that names the actor leaves it off\n\t\t * the line under it. An action without a label shows as written.\n\t\t *\n\t\t * @type {Object<string, string>|null}\n\t\t */\n\t\tactionLabels: { type: Object, default: null },\n\t\t/**\n\t\t * Words for the values an action label quotes as `{changed.<key>}`:\n\t\t * `{ purpose: { handling: 'Handling' } }`. A value without an entry\n\t\t * shows as written.\n\t\t *\n\t\t * @type {{[key: string]: {[value: string]: string}}|null}\n\t\t */\n\t\tvalueLabels: { type: Object, default: null },\n\t\t/**\n\t\t * What happened, in words, by the field an entry changed: rules\n\t\t * `[{ action?, field, to?, label }]`, the first whose `field` the entry\n\t\t * changed (to `to`, when given) wins over `actionLabels`. A label fills\n\t\t * the same tokens, plus `{object.<path>}` from `object`\n\t\t * (\"Version {object.version} published\" for `isDraft` set to false).\n\t\t *\n\t\t * @type {Array<{action?: string, field: string, to?: unknown, label: string}>}\n\t\t */\n\t\tchangeLabels: { type: Array, default: () => [] },\n\t\t/** The audited record, for `{object.<path>}` in a label; null without one. */\n\t\tobject: { type: Object, default: null },\n\t\t/**\n\t\t * Records beside the object whose events belong in its history:\n\t\t * `[{ as, register, schema, filter, limit? }]`. The card lists the\n\t\t * objects matching `filter` (`@objectId` is this object; at most\n\t\t * `limit`, default 5), reads their trails and merges the entries with\n\t\t * the object's own, newest first. A related entry is labelled by\n\t\t * `actionLabels[\"<as>.<action>\"]` first. Object scope only.\n\t\t *\n\t\t * @type {Array<{as: string, register: string, schema: string, filter?: object, limit?: number}>}\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\trelatedSources: { type: Array, default: () => [] },\n\t\t/** Shown when a `source` or `endpoint` read failed. */\n\t\tfailedLabel: { type: String, default: () => t('nextcloud-vue', 'The history could not be loaded') },\n\t},\n\n\temits: ['show-all'],\n\n\tdata() {\n\t\treturn {\n\t\t\tHistory: markRaw(History),\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\t/** A `source` or `endpoint` read failed: said, rather than shown as an empty trail. */\n\t\t\tfailed: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Audit trail')\n\t\t},\n\n\t\t/** @return {Array<object>} The entries without the excluded actions. */\n\t\tshownEntries() {\n\t\t\tconst excluded = this.excludeActions.map((action) => String(action).toLowerCase())\n\t\t\tif (excluded.length === 0) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.filter((entry) => !excluded.includes(String(entry.action || entry.event || '').toLowerCase()))\n\t\t},\n\n\t\tdisplayedEntries() {\n\t\t\tconst entries = this.oldestFirst ? [...this.shownEntries].sort((a, b) => entryTime(a) - entryTime(b)) : this.shownEntries\n\t\t\treturn entries.slice(0, this.maxDisplay)\n\t\t},\n\n\t\t/**\n\t\t * The trail URL a `source` or `endpoint` names, '' while its record id\n\t\t * is unknown, or null when the card reads an object.\n\t\t *\n\t\t * @return {string|null}\n\t\t * @spec openspec/changes/leaf-cards-read-a-source/specs/leaf-cards-read-a-source/spec.md#requirement-a-leaf-card-reads-a-source-or-an-endpoint\n\t\t */\n\t\tsourceUrl() {\n\t\t\treturn leafSourceUrl({ source: this.source, endpoint: this.endpoint, apiBase: this.apiBase, objectId: this.objectId }, 'audit')\n\t\t},\n\n\t\t/** @return {boolean} Whether the entries read oldest first. */\n\t\toldestFirst() {\n\t\t\treturn this.order === 'oldest' || (this.order === '' && this.sourceUrl !== null)\n\t\t},\n\n\t\t/**\n\t\t * The path the card reads (prefixed at fetch time), or '' when it has nothing to read: the\n\t\t * object's own trail, or the app-wide readable feed narrowed to the\n\t\t * register and schema when set.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {string}\n\t\t */\n\t\tfetchUrl() {\n\t\t\tif (this.sourceUrl !== null) {\n\t\t\t\treturn this.sourceUrl\n\t\t\t}\n\t\t\tconst limit = this.excludeActions.length > 0 ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay\n\t\t\tconst params = new URLSearchParams({ limit: String(limit) })\n\t\t\tif (this.scope === 'app') {\n\t\t\t\tif (this.register) {\n\t\t\t\t\tparams.set('register', this.register)\n\t\t\t\t}\n\t\t\t\tif (this.schema) {\n\t\t\t\t\tparams.set('schema', this.schema)\n\t\t\t\t}\n\t\t\t\treturn `${this.apiBase}/audit-trails/readable?${params.toString()}`\n\t\t\t}\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails?${params.toString()}`\n\t\t},\n\t},\n\n\twatch: {\n\t\tfetchUrl: {\n\t\t\timmediate: true,\n\t\t\thandler(url) {\n\t\t\t\tif (url) {\n\t\t\t\t\tthis.fetchEntries()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the entries from `fetchUrl`. The readable feed answers\n\t\t * `{ rows, nextCursor }`, the object trail `{ results }`.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchEntries() {\n\t\t\tconst url = this.fetchUrl\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst list = data.results || data.rows || data\n\t\t\t\t\tconst own = Array.isArray(list) ? list : []\n\t\t\t\t\tconst related = await this.fetchRelatedEntries()\n\t\t\t\t\tthis.entries = related.length > 0\n\t\t\t\t\t\t? [...own, ...related].sort((a, b) => entryTime(b) - entryTime(a))\n\t\t\t\t\t\t: own\n\t\t\t\t} else {\n\t\t\t\t\tthis.entries = []\n\t\t\t\t\tthis.failed = this.sourceUrl !== null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnAuditTrailCard] failed to fetch audit trail', err)\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.failed = this.sourceUrl !== null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The entries of the records beside the object (`relatedSources`),\n\t\t * each tagged with its source's `as`. A read that fails leaves that\n\t\t * source out.\n\t\t *\n\t\t * @return {Promise<Array<object>>} The entries.\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\tasync fetchRelatedEntries() {\n\t\t\tif (this.scope !== 'object' || this.sourceUrl !== null || !this.objectId || !Array.isArray(this.relatedSources)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst limit = this.excludeActions.length > 0 ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay\n\t\t\tconst read = async (url) => {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(String(response.status))\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = data.results || data.rows || data\n\t\t\t\treturn Array.isArray(list) ? list : []\n\t\t\t}\n\t\t\tconst perSource = await Promise.all(this.relatedSources\n\t\t\t\t.filter((source) => source && source.register && source.schema)\n\t\t\t\t.map(async (source) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst params = new URLSearchParams({ _limit: String(Number(source.limit) > 0 ? Number(source.limit) : 5), _order: JSON.stringify({ '@self.created': 'DESC' }) })\n\t\t\t\t\t\tfor (const [key, value] of Object.entries(source.filter || {})) {\n\t\t\t\t\t\t\tparams.set(key, value === '@objectId' ? this.objectId : String(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst objects = await read(`${this.apiBase}/objects/${source.register}/${source.schema}?${params.toString()}`)\n\t\t\t\t\t\tconst ids = objects.map((object) => object?.id || object?.['@self']?.id || object?.uuid).filter(Boolean)\n\t\t\t\t\t\tconst trails = await Promise.all(ids.map((id) => read(`${this.apiBase}/objects/${source.register}/${source.schema}/${id}/audit-trails?limit=${limit}`).catch(() => [])))\n\t\t\t\t\t\treturn trails.flat().map((entry) => ({ ...entry, relatedAs: source.as || source.schema }))\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn []\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\treturn perSource.flat()\n\t\t},\n\n\t\t/**\n\t\t * What happened: the action, with the state it led to when the entry\n\t\t * names one (a flow task's `stateAfter`).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t */\n\t\tformatAction(entry) {\n\t\t\tconst label = this.changeLabelFor(entry) ?? this.labelFor(entry)\n\t\t\tif (label !== null) {\n\t\t\t\treturn label\n\t\t\t\t\t.replace('{actor}', this.actorName(entry))\n\t\t\t\t\t.replace('{state}', entry.stateAfter || '')\n\t\t\t\t\t.replace(/\\{changed\\.([\\w-]+)\\}/g, (match, key) => this.changedValue(entry, key))\n\t\t\t\t\t.replace(/\\{object\\.([\\w.-]+)\\}/g, (match, path) => {\n\t\t\t\t\t\tconst value = this.object ? readPath(this.object, path) : undefined\n\t\t\t\t\t\treturn value === null || value === undefined || typeof value === 'object' ? '' : String(value)\n\t\t\t\t\t})\n\t\t\t}\n\t\t\tconst action = entry.action || entry.event || this.actionLabel\n\t\t\treturn entry.stateAfter ? `${action} (${entry.stateAfter})` : action\n\t\t},\n\n\t\t/**\n\t\t * A value the entry recorded under `changed` (an audit entry's context),\n\t\t * in the words of `valueLabels`; '' when it recorded none.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {string} key The recorded key.\n\t\t * @return {string} The value in words.\n\t\t * @spec openspec/changes/audit-label-changed-values/specs/audit-trail/spec.md#requirement-a-trail-label-can-quote-what-the-entry-recorded\n\t\t */\n\t\tchangedValue(entry, key) {\n\t\t\tconst changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {}\n\t\t\tconst value = newValueOf(changed[key])\n\t\t\tif (value === null || value === undefined || typeof value === 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst words = this.valueLabels && this.valueLabels[key]\n\t\t\treturn words && typeof words[value] === 'string' ? words[value] : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The `changeLabels` rule an entry matches: the first whose field the\n\t\t * entry changed, for its action and to its value when the rule names them.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string|null} The label, or null when no rule matches.\n\t\t */\n\t\tchangeLabelFor(entry) {\n\t\t\tconst changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {}\n\t\t\tconst action = entry.action || entry.event || ''\n\t\t\tfor (const rule of Array.isArray(this.changeLabels) ? this.changeLabels : []) {\n\t\t\t\tif (!rule || typeof rule.label !== 'string' || rule.label === '' || typeof rule.field !== 'string' || !Object.hasOwn(changed, rule.field)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (rule.action && rule.action !== action) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (Object.hasOwn(rule, 'to') && String(newValueOf(changed[rule.field])) !== String(rule.to)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn rule.label\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The `actionLabels` entry for an entry: by action and state first,\n\t\t * then by action.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string|null} The label, or null when none is declared.\n\t\t * @spec openspec/changes/audit-trail-action-labels/specs/audit-trail/spec.md#requirement-a-trail-can-say-what-happened-in-words\n\t\t */\n\t\tlabelFor(entry) {\n\t\t\tconst labels = this.actionLabels\n\t\t\tconst action = entry.action || entry.event\n\t\t\tif (!labels || !action) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst state = entry.stateAfter || ''\n\t\t\tconst prefix = entry.relatedAs ? `${entry.relatedAs}.` : ''\n\t\t\tconst label = (prefix ? (labels[`${prefix}${action}:${state}`] ?? labels[`${prefix}${action}`]) : undefined)\n\t\t\t\t?? labels[`${action}:${state}`] ?? labels[action]\n\t\t\treturn typeof label === 'string' && label !== '' ? label : null\n\t\t},\n\n\t\t/**\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} Who did it, by name where the entry carries one.\n\t\t */\n\t\tactorName(entry) {\n\t\t\tif (entry.actorDisplayName) {\n\t\t\t\treturn entry.actorDisplayName\n\t\t\t}\n\t\t\tconst id = entry.actor || entry.userId || entry.user || ''\n\t\t\t// A person's user id reads as their display name once it is known.\n\t\t\treturn (id && (!entry.performerType || entry.performerType === 'user') && userDisplayName(String(id))) || id\n\t\t},\n\n\t\t/**\n\t\t * The muted line of a stacked row: the moment in the board's short\n\t\t * form (\"6 okt 09:05\") and who, unless the action names them already.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t * @spec openspec/changes/audit-card-stacked-rows/specs/audit-trail/spec.md#requirement-an-audit-row-can-put-its-moment-under-the-action\n\t\t */\n\t\tstackedLine(entry) {\n\t\t\tconst raw = entry.creationDateTime || entry.created || entry.timestamp\n\t\t\tconst date = raw ? new Date(raw) : null\n\t\t\tconst when = date && !Number.isNaN(date.getTime()) ? `${formatBoardDate(date)} ${formatTimeOfDay(date)}` : ''\n\t\t\treturn [when, this.formatActor(entry)].filter((part) => part !== '').join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * Who did it: the actor, the kind of performer when it is not a\n\t\t * person (a flow, the system), and on whose behalf.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t */\n\t\tformatActor(entry) {\n\t\t\tconst named = (this.labelFor(entry) || '').includes('{actor}')\n\t\t\tconst parts = [named ? '' : this.actorName(entry)]\n\t\t\tif (entry.performerType && entry.performerType !== 'user') {\n\t\t\t\tparts.push(`(${entry.performerType})`)\n\t\t\t}\n\t\t\tif (entry.onBehalfOf) {\n\t\t\t\tparts.push(t('nextcloud-vue', 'on behalf of {name}', { name: entry.onBehalfOf }))\n\t\t\t}\n\t\t\treturn parts.filter((part) => part !== '').join(' ')\n\t\t},\n\n\t\tformatWhen(entry) {\n\t\t\tconst raw = entry.creationDateTime || entry.created || entry.timestamp\n\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst d = new Date(raw)\n\t\t\tif (Number.isNaN(d.getTime()) === true) {\n\t\t\t\treturn String(raw)\n\t\t\t}\n\t\t\treturn d.toLocaleString(userLocale())\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-audit-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-audit-card__row {\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-audit-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-audit-card__row-head {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-audit-card__action {\n\tcolor: var(--color-main-text);\n}\n\n.cn-audit-card__when {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\twhite-space: nowrap;\n}\n\n.cn-audit-card__row-body {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-audit-card__refused {\n\tmargin-inline-start: 6px;\n\tfont-weight: 700;\n\tcolor: var(--color-error-text, var(--color-main-text));\n}\n\n.cn-audit-card__reason {\n\tmargin: 2px 0 0;\n\tfont-size: 0.9em;\n\toverflow-wrap: anywhere;\n}\n\n.cn-audit-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n\n.cn-audit-card__footnote {\n\tmargin: 12px 0 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-audit-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tcursor: pointer;\n\tpadding: 4px 0;\n\tfont: inherit;\n}\n\n.cn-audit-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_toDisplayString","_openBlock","_normalizeClass","_createElementVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnAuditTrailCard.vue3.js","sources":["../../../../src/components/CnAuditTrailCard/CnAuditTrailCard.vue?vue&type=template&id=bd3033c8&lang.js"],"sourcesContent":["<!--\n CnAuditTrailCard — compact audit-trail widget for the integration\n registry.\n\n Surface-aware shell around the `audit-trail` integration: fetches\n the object's recent audit-trail entries (query-time storage strategy\n per AD-22) and renders them in a CnDetailCard.\n\n Per umbrella change `pluggable-integration-registry` AD-19 (surface\n fallback), one component handles all surfaces — `surface` is\n forwarded so the component can branch internally if desired.\n-->\n<template>\n\t<CnDetailCard\n\t\t:title=\"resolvedTitle\"\n\t\t:icon=\"History\"\n\t\t:collapsible=\"collapsible\"\n\t\t:data-surface=\"surface\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<p v-else-if=\"failed\"\n\t\t\tclass=\"cn-audit-card__empty\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-audit-card-failed\">\n\t\t\t{{ failedLabel }}\n\t\t</p>\n\t\t<div v-else-if=\"shownEntries.length === 0\" class=\"cn-audit-card__empty\">\n\t\t\t{{ noEntriesLabel }}\n\t\t</div>\n\t\t<ul v-else class=\"cn-audit-card__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"entry in displayedEntries\"\n\t\t\t\t:key=\"entry.id\"\n\t\t\t\tclass=\"cn-audit-card__row\"\n\t\t\t\t:class=\"{ 'cn-audit-card__row--stacked': layout === 'stacked' }\">\n\t\t\t\t<div class=\"cn-audit-card__row-head\">\n\t\t\t\t\t<strong class=\"cn-audit-card__action\">{{ formatAction(entry) }}</strong>\n\t\t\t\t\t<span v-if=\"layout !== 'stacked'\" class=\"cn-audit-card__when\">{{ formatWhen(entry) }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-audit-card__row-body\">\n\t\t\t\t\t<span v-if=\"layout === 'stacked'\" class=\"cn-audit-card__when\" data-testid=\"cn-audit-card-when-below\">{{ stackedLine(entry) }}</span>\n\t\t\t\t\t<span v-else class=\"cn-audit-card__actor\">{{ formatActor(entry) }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"entry.authorized === false\"\n\t\t\t\t\t\tclass=\"cn-audit-card__refused\"\n\t\t\t\t\t\tdata-testid=\"cn-audit-card-refused\">{{ refusedLabel }}</span>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"entry.reason\" class=\"cn-audit-card__reason\">\n\t\t\t\t\t{{ entry.reason }}\n\t\t\t\t</p>\n\t\t\t</li>\n\t\t</ul>\n\t\t<p v-if=\"footnote\" class=\"cn-audit-card__footnote\" data-testid=\"cn-audit-trail-widget-footnote\">\n\t\t\t{{ footnote }}\n\t\t</p>\n\t\t<template v-if=\"shownEntries.length > maxDisplay\" #footer>\n\t\t\t<button class=\"cn-audit-card__show-all\" @click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ shownEntries.length }})\n\t\t\t</button>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport History from 'vue-material-design-icons/History.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport { formatBoardDate, formatTimeOfDay } from '../../utils/boardDate.js'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { leafSourceUrl } from '../../utils/leafSourceUrl.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { userDisplayName } from '../../utils/userDisplayName.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * A changed value as an entry records it: OpenRegister writes `{ old, new }`,\n * other sources the value itself.\n *\n * @param {unknown} value The recorded change.\n * @return {unknown} The value it changed to.\n */\nfunction newValueOf(value) {\n\treturn value !== null && typeof value === 'object' && Object.hasOwn(value, 'new') ? value.new : value\n}\n\n/**\n * @param {object} entry An audit entry.\n * @return {number} When it happened, in ms; 0 when unreadable.\n */\nfunction entryTime(entry) {\n\tconst time = new Date(entry.creationDateTime || entry.created || entry.timestamp || 0).getTime()\n\treturn Number.isNaN(time) ? 0 : time\n}\n\n/**\n * CnAuditTrailCard — compact audit-trail widget rendered by the\n * integration registry on dashboard and detail surfaces.\n *\n * Basic usage\n * ```vue\n * <CnAuditTrailCard\n * :register=\"registerId\"\n * :schema=\"schemaId\"\n * :object-id=\"objectId\"\n * surface=\"detail-page\" />\n * ```\n */\nexport default {\n\tname: 'CnAuditTrailCard',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon },\n\n\tprops: {\n\t\t/**\n\t\t * A muted line under the trail, inside the card (\"Kenmerk ZT-OMV-REG\").\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-footnote/specs/audit-trail/spec.md#requirement-a-history-card-can-end-in-a-line-about-the-record\n\t\t */\n\t\tfootnote: { type: String, default: '' },\n\t\t/** OpenRegister register id (slug or uuid). Optional for `scope: \"app\"`. */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema id (slug or uuid). Optional for `scope: \"app\"`. */\n\t\tschema: { type: String, default: '' },\n\t\t/** Parent object id. Required for `scope: \"object\"` (the default); unused for `scope: \"app\"`. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/**\n\t\t * What the card lists. `object` (the default) is one object's trail\n\t\t * and needs `register`, `schema` and `objectId`. `app` is the\n\t\t * app-wide feed: the entries of every object the caller may read\n\t\t * (OpenRegister's `/audit-trails/readable`), narrowed to `register`\n\t\t * and `schema` when those are set.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t */\n\t\tscope: {\n\t\t\ttype: String,\n\t\t\tdefault: 'object',\n\t\t\tvalidator: (value) => ['object', 'app'].includes(value),\n\t\t},\n\n\t\t/** Rendering surface — passed for AD-19 surface fallback consumers. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (value) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(value),\n\t\t},\n\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\n\t\t/**\n\t\t * Read the trail of something that is not an OpenRegister object:\n\t\t * `{ kind: 'flow-task', id }` reads `${apiBase}/flow-tasks/{id}/audit`,\n\t\t * oldest first. `id` may be left out or written `@objectId`.\n\t\t *\n\t\t * @type {{kind: string, id?: (string|number)}|null}\n\t\t */\n\t\tsource: { type: Object, default: null },\n\n\t\t/** A trail URL that replaces the object's own; `{id}` is filled with the source's id or `objectId`. */\n\t\tendpoint: { type: String, default: '' },\n\n\t\t/** `newest` first (the object trail's order) or `oldest` first; empty takes `oldest` for a source and `newest` otherwise. */\n\t\torder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t\tvalidator: (value) => ['', 'newest', 'oldest'].includes(value),\n\t\t},\n\n\t\t/** Maximum rows to render. */\n\t\tmaxDisplay: { type: Number, default: 5 },\n\t\t/**\n\t\t * `stacked` (DqTaak \"Historie\"): the action, then one muted line under\n\t\t * it with the moment (\"6 okt 09:05\") and who, when the action does not\n\t\t * already name them. Default: the moment beside the action, who under it.\n\t\t */\n\t\tlayout: { type: String, default: '' },\n\t\t/**\n\t\t * Actions the card leaves out (case-insensitive), such as `['read']`\n\t\t * for a history of what changed. It then reads more entries than it\n\t\t * shows, so the rows it leaves out do not crowd the rest away.\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-exclude-actions/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-events-by-action\n\t\t */\n\t\texcludeActions: { type: Array, default: () => [] },\n\t\t/**\n\t\t * Actors the card leaves out by user id (case-insensitive), such as\n\t\t * `['System']` for a history of what people did: the bookkeeping a\n\t\t * background job writes is not shown.\n\t\t *\n\t\t * @spec openspec/changes/audit-card-exclude-actors/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-entries-by-actor\n\t\t */\n\t\texcludeActors: { type: Array, default: () => [] },\n\t\t/** Whether the card collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Pre-translated empty label. */\n\t\tnoEntriesLabel: { type: String, default: () => t('nextcloud-vue', 'No audit entries yet') },\n\t\t/** Pre-translated overflow label. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/** Pre-translated fallback action label. */\n\t\tactionLabel: { type: String, default: () => t('nextcloud-vue', 'Change') },\n\t\t/** Shown on an entry the server refused (`authorized: false`). */\n\t\trefusedLabel: { type: String, default: () => t('nextcloud-vue', '(refused)') },\n\t\t/**\n\t\t * What happened, in words, by action (`claim`) or by action and the\n\t\t * state it led to (`complete:completed`, tried first). `{actor}`,\n\t\t * `{state}` and `{changed.<key>}` (a value the entry recorded, a dotted key\n\t\t * reading into it such as `{changed.data.fileName}`, in the\n\t\t * words of `valueLabels`) are filled in; a label that names the actor leaves it off\n\t\t * the line under it. An action without a label shows as written.\n\t\t *\n\t\t * @type {Object<string, string>|null}\n\t\t */\n\t\tactionLabels: { type: Object, default: null },\n\t\t/**\n\t\t * Words for the values an action label quotes as `{changed.<key>}`:\n\t\t * `{ purpose: { handling: 'Handling' } }`. A value without an entry\n\t\t * shows as written.\n\t\t *\n\t\t * @type {{[key: string]: {[value: string]: string}}|null}\n\t\t */\n\t\tvalueLabels: { type: Object, default: null },\n\t\t/**\n\t\t * What happened, in words, by the field an entry changed: rules\n\t\t * `[{ action?, field, to?, label }]`, the first whose `field` the entry\n\t\t * changed (to `to`, when given) wins over `actionLabels`. A label fills\n\t\t * the same tokens, plus `{object.<path>}` from `object`\n\t\t * (\"Version {object.version} published\" for `isDraft` set to false).\n\t\t *\n\t\t * @type {Array<{action?: string, field: string, to?: unknown, label: string}>}\n\t\t */\n\t\tchangeLabels: { type: Array, default: () => [] },\n\t\t/** The audited record, for `{object.<path>}` in a label; null without one. */\n\t\tobject: { type: Object, default: null },\n\t\t/**\n\t\t * Records beside the object whose events belong in its history:\n\t\t * `[{ as, register, schema, filter, limit? }]`. The card lists the\n\t\t * objects matching `filter` (`@objectId` is this object; at most\n\t\t * `limit`, default 5), reads their trails and merges the entries with\n\t\t * the object's own, newest first. A related entry is labelled by\n\t\t * `actionLabels[\"<as>.<action>\"]` first. Object scope only.\n\t\t *\n\t\t * @type {Array<{as: string, register: string, schema: string, filter?: object, limit?: number}>}\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\trelatedSources: { type: Array, default: () => [] },\n\t\t/** Shown when a `source` or `endpoint` read failed. */\n\t\tfailedLabel: { type: String, default: () => t('nextcloud-vue', 'The history could not be loaded') },\n\t},\n\n\temits: ['show-all'],\n\n\tdata() {\n\t\treturn {\n\t\t\tHistory: markRaw(History),\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\t/** A `source` or `endpoint` read failed: said, rather than shown as an empty trail. */\n\t\t\tfailed: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Audit trail')\n\t\t},\n\n\t\t/** @return {Array<object>} The entries without the excluded actions. */\n\t\tshownEntries() {\n\t\t\tconst excluded = this.excludeActions.map((action) => String(action).toLowerCase())\n\t\t\tconst actors = this.excludeActors.map((actor) => String(actor).toLowerCase())\n\t\t\tif (excluded.length === 0 && actors.length === 0) {\n\t\t\t\treturn this.entries\n\t\t\t}\n\t\t\treturn this.entries.filter((entry) => !excluded.includes(String(entry.action || entry.event || '').toLowerCase())\n\t\t\t\t&& !actors.includes(String(entry.user || '').toLowerCase()))\n\t\t},\n\n\t\t/** @return {boolean} Whether the card leaves entries out, and so reads more than it shows. */\n\t\tfiltersEntries() {\n\t\t\treturn this.excludeActions.length > 0 || this.excludeActors.length > 0\n\t\t},\n\n\t\tdisplayedEntries() {\n\t\t\tconst entries = this.oldestFirst ? [...this.shownEntries].sort((a, b) => entryTime(a) - entryTime(b)) : this.shownEntries\n\t\t\treturn entries.slice(0, this.maxDisplay)\n\t\t},\n\n\t\t/**\n\t\t * The trail URL a `source` or `endpoint` names, '' while its record id\n\t\t * is unknown, or null when the card reads an object.\n\t\t *\n\t\t * @return {string|null}\n\t\t * @spec openspec/changes/leaf-cards-read-a-source/specs/leaf-cards-read-a-source/spec.md#requirement-a-leaf-card-reads-a-source-or-an-endpoint\n\t\t */\n\t\tsourceUrl() {\n\t\t\treturn leafSourceUrl({ source: this.source, endpoint: this.endpoint, apiBase: this.apiBase, objectId: this.objectId }, 'audit')\n\t\t},\n\n\t\t/** @return {boolean} Whether the entries read oldest first. */\n\t\toldestFirst() {\n\t\t\treturn this.order === 'oldest' || (this.order === '' && this.sourceUrl !== null)\n\t\t},\n\n\t\t/**\n\t\t * The path the card reads (prefixed at fetch time), or '' when it has nothing to read: the\n\t\t * object's own trail, or the app-wide readable feed narrowed to the\n\t\t * register and schema when set.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {string}\n\t\t */\n\t\tfetchUrl() {\n\t\t\tif (this.sourceUrl !== null) {\n\t\t\t\treturn this.sourceUrl\n\t\t\t}\n\t\t\tconst limit = this.filtersEntries ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay\n\t\t\tconst params = new URLSearchParams({ limit: String(limit) })\n\t\t\tif (this.scope === 'app') {\n\t\t\t\tif (this.register) {\n\t\t\t\t\tparams.set('register', this.register)\n\t\t\t\t}\n\t\t\t\tif (this.schema) {\n\t\t\t\t\tparams.set('schema', this.schema)\n\t\t\t\t}\n\t\t\t\treturn `${this.apiBase}/audit-trails/readable?${params.toString()}`\n\t\t\t}\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails?${params.toString()}`\n\t\t},\n\t},\n\n\twatch: {\n\t\tfetchUrl: {\n\t\t\timmediate: true,\n\t\t\thandler(url) {\n\t\t\t\tif (url) {\n\t\t\t\t\tthis.fetchEntries()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the entries from `fetchUrl`. The readable feed answers\n\t\t * `{ rows, nextCursor }`, the object trail `{ results }`.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchEntries() {\n\t\t\tconst url = this.fetchUrl\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst list = data.results || data.rows || data\n\t\t\t\t\tconst own = Array.isArray(list) ? list : []\n\t\t\t\t\tconst related = await this.fetchRelatedEntries()\n\t\t\t\t\tthis.entries = related.length > 0\n\t\t\t\t\t\t? [...own, ...related].sort((a, b) => entryTime(b) - entryTime(a))\n\t\t\t\t\t\t: own\n\t\t\t\t} else {\n\t\t\t\t\tthis.entries = []\n\t\t\t\t\tthis.failed = this.sourceUrl !== null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnAuditTrailCard] failed to fetch audit trail', err)\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.failed = this.sourceUrl !== null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The entries of the records beside the object (`relatedSources`),\n\t\t * each tagged with its source's `as`. A read that fails leaves that\n\t\t * source out.\n\t\t *\n\t\t * @return {Promise<Array<object>>} The entries.\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\tasync fetchRelatedEntries() {\n\t\t\tif (this.scope !== 'object' || this.sourceUrl !== null || !this.objectId || !Array.isArray(this.relatedSources)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst limit = this.filtersEntries ? Math.min(100, this.maxDisplay * 10) : this.maxDisplay\n\t\t\tconst read = async (url) => {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(String(response.status))\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = data.results || data.rows || data\n\t\t\t\treturn Array.isArray(list) ? list : []\n\t\t\t}\n\t\t\tconst perSource = await Promise.all(this.relatedSources\n\t\t\t\t.filter((source) => source && source.register && source.schema)\n\t\t\t\t.map(async (source) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst params = new URLSearchParams({ _limit: String(Number(source.limit) > 0 ? Number(source.limit) : 5), _order: JSON.stringify({ '@self.created': 'DESC' }) })\n\t\t\t\t\t\tfor (const [key, value] of Object.entries(source.filter || {})) {\n\t\t\t\t\t\t\tparams.set(key, value === '@objectId' ? this.objectId : String(value))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst objects = await read(`${this.apiBase}/objects/${source.register}/${source.schema}?${params.toString()}`)\n\t\t\t\t\t\tconst ids = objects.map((object) => object?.id || object?.['@self']?.id || object?.uuid).filter(Boolean)\n\t\t\t\t\t\tconst trails = await Promise.all(ids.map((id) => read(`${this.apiBase}/objects/${source.register}/${source.schema}/${id}/audit-trails?limit=${limit}`).catch(() => [])))\n\t\t\t\t\t\treturn trails.flat().map((entry) => ({ ...entry, relatedAs: source.as || source.schema }))\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn []\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\treturn perSource.flat()\n\t\t},\n\n\t\t/**\n\t\t * What happened: the action, with the state it led to when the entry\n\t\t * names one (a flow task's `stateAfter`).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t */\n\t\tformatAction(entry) {\n\t\t\tconst label = this.changeLabelFor(entry) ?? this.labelFor(entry)\n\t\t\tif (label !== null) {\n\t\t\t\treturn label\n\t\t\t\t\t.replace('{actor}', this.actorName(entry))\n\t\t\t\t\t.replace('{state}', entry.stateAfter || '')\n\t\t\t\t\t.replace(/\\{changed\\.([\\w.-]+)\\}/g, (match, key) => this.changedValue(entry, key))\n\t\t\t\t\t.replace(/\\{object\\.([\\w.-]+)\\}/g, (match, path) => {\n\t\t\t\t\t\tconst value = this.object ? readPath(this.object, path) : undefined\n\t\t\t\t\t\treturn value === null || value === undefined || typeof value === 'object' ? '' : String(value)\n\t\t\t\t\t})\n\t\t\t}\n\t\t\tconst action = entry.action || entry.event || this.actionLabel\n\t\t\treturn entry.stateAfter ? `${action} (${entry.stateAfter})` : action\n\t\t},\n\n\t\t/**\n\t\t * A value the entry recorded under `changed` (an audit entry's context),\n\t\t * in the words of `valueLabels`; '' when it recorded none.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {string} key The recorded key.\n\t\t * @return {string} The value in words.\n\t\t * @spec openspec/changes/audit-label-changed-values/specs/audit-trail/spec.md#requirement-a-trail-label-can-quote-what-the-entry-recorded\n\t\t */\n\t\tchangedValue(entry, key) {\n\t\t\tconst changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {}\n\t\t\t// A dotted key reads into what the entry recorded (`data.fileName` on a file action).\n\t\t\tconst value = String(key).split('.').reduce((at, part) => newValueOf(at !== null && typeof at === 'object' ? at[part] : undefined), changed)\n\t\t\tif (value === null || value === undefined || typeof value === 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst words = this.valueLabels && this.valueLabels[key]\n\t\t\treturn words && typeof words[value] === 'string' ? words[value] : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The `changeLabels` rule an entry matches: the first whose field the\n\t\t * entry changed, for its action and to its value when the rule names them.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string|null} The label, or null when no rule matches.\n\t\t */\n\t\tchangeLabelFor(entry) {\n\t\t\tconst changed = entry && typeof entry.changed === 'object' && entry.changed !== null ? entry.changed : {}\n\t\t\tconst action = entry.action || entry.event || ''\n\t\t\tfor (const rule of Array.isArray(this.changeLabels) ? this.changeLabels : []) {\n\t\t\t\tif (!rule || typeof rule.label !== 'string' || rule.label === '' || typeof rule.field !== 'string' || !Object.hasOwn(changed, rule.field)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (rule.action && rule.action !== action) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (Object.hasOwn(rule, 'to') && String(newValueOf(changed[rule.field])) !== String(rule.to)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn rule.label\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The `actionLabels` entry for an entry: by action and state first,\n\t\t * then by action.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string|null} The label, or null when none is declared.\n\t\t * @spec openspec/changes/audit-trail-action-labels/specs/audit-trail/spec.md#requirement-a-trail-can-say-what-happened-in-words\n\t\t */\n\t\tlabelFor(entry) {\n\t\t\tconst labels = this.actionLabels\n\t\t\tconst action = entry.action || entry.event\n\t\t\tif (!labels || !action) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst state = entry.stateAfter || ''\n\t\t\tconst prefix = entry.relatedAs ? `${entry.relatedAs}.` : ''\n\t\t\tconst label = (prefix ? (labels[`${prefix}${action}:${state}`] ?? labels[`${prefix}${action}`]) : undefined)\n\t\t\t\t?? labels[`${action}:${state}`] ?? labels[action]\n\t\t\treturn typeof label === 'string' && label !== '' ? label : null\n\t\t},\n\n\t\t/**\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} Who did it, by name where the entry carries one.\n\t\t */\n\t\tactorName(entry) {\n\t\t\tif (entry.actorDisplayName) {\n\t\t\t\treturn entry.actorDisplayName\n\t\t\t}\n\t\t\tconst id = entry.actor || entry.userId || entry.user || ''\n\t\t\t// A person's user id reads as their display name once it is known.\n\t\t\treturn (id && (!entry.performerType || entry.performerType === 'user') && userDisplayName(String(id))) || id\n\t\t},\n\n\t\t/**\n\t\t * The muted line of a stacked row: the moment in the board's short\n\t\t * form (\"6 okt 09:05\") and who, unless the action names them already.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t * @spec openspec/changes/audit-card-stacked-rows/specs/audit-trail/spec.md#requirement-an-audit-row-can-put-its-moment-under-the-action\n\t\t */\n\t\tstackedLine(entry) {\n\t\t\tconst raw = entry.creationDateTime || entry.created || entry.timestamp\n\t\t\tconst date = raw ? new Date(raw) : null\n\t\t\tconst when = date && !Number.isNaN(date.getTime()) ? `${formatBoardDate(date)} ${formatTimeOfDay(date)}` : ''\n\t\t\treturn [when, this.formatActor(entry)].filter((part) => part !== '').join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * Who did it: the actor, the kind of performer when it is not a\n\t\t * person (a flow, the system), and on whose behalf.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The line.\n\t\t */\n\t\tformatActor(entry) {\n\t\t\tconst named = (this.labelFor(entry) || '').includes('{actor}')\n\t\t\tconst parts = [named ? '' : this.actorName(entry)]\n\t\t\tif (entry.performerType && entry.performerType !== 'user') {\n\t\t\t\tparts.push(`(${entry.performerType})`)\n\t\t\t}\n\t\t\tif (entry.onBehalfOf) {\n\t\t\t\tparts.push(t('nextcloud-vue', 'on behalf of {name}', { name: entry.onBehalfOf }))\n\t\t\t}\n\t\t\treturn parts.filter((part) => part !== '').join(' ')\n\t\t},\n\n\t\tformatWhen(entry) {\n\t\t\tconst raw = entry.creationDateTime || entry.created || entry.timestamp\n\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst d = new Date(raw)\n\t\t\tif (Number.isNaN(d.getTime()) === true) {\n\t\t\t\treturn String(raw)\n\t\t\t}\n\t\t\treturn d.toLocaleString(userLocale())\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-audit-card__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-audit-card__row {\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-audit-card__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-audit-card__row-head {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-audit-card__action {\n\tcolor: var(--color-main-text);\n}\n\n.cn-audit-card__when {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\twhite-space: nowrap;\n}\n\n.cn-audit-card__row-body {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-audit-card__refused {\n\tmargin-inline-start: 6px;\n\tfont-weight: 700;\n\tcolor: var(--color-error-text, var(--color-main-text));\n}\n\n.cn-audit-card__reason {\n\tmargin: 2px 0 0;\n\tfont-size: 0.9em;\n\toverflow-wrap: anywhere;\n}\n\n.cn-audit-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n\n.cn-audit-card__footnote {\n\tmargin: 12px 0 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-audit-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tcursor: pointer;\n\tpadding: 4px 0;\n\tfont: inherit;\n}\n\n.cn-audit-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_toDisplayString","_openBlock","_normalizeClass","_createElementVNode"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnAuditTrailWidget.vue2.js';
|
|
|
2
2
|
import { render } from './CnAuditTrailWidget.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-99c9557e";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -74,7 +74,7 @@ var script = {
|
|
|
74
74
|
excludeActions: { type: Array, default: () => [] },
|
|
75
75
|
/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, footnote? }`. */
|
|
76
76
|
/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, valueLabels? }`. */
|
|
77
|
-
/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, valueLabels?, relatedSources? }`. */
|
|
77
|
+
/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, valueLabels?, relatedSources?, excludeActors? }`. */
|
|
78
78
|
content: { type: Object, default: () => ({}) },
|
|
79
79
|
},
|
|
80
80
|
|
|
@@ -248,6 +248,17 @@ var script = {
|
|
|
248
248
|
return Array.isArray(fromContent) ? fromContent.filter((action) => typeof action === 'string' && action !== '') : []
|
|
249
249
|
},
|
|
250
250
|
|
|
251
|
+
/**
|
|
252
|
+
* The actors to leave out, from `content.excludeActors`.
|
|
253
|
+
*
|
|
254
|
+
* @spec openspec/changes/audit-card-exclude-actors/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-entries-by-actor
|
|
255
|
+
* @return {Array<string>}
|
|
256
|
+
*/
|
|
257
|
+
resolvedExcludeActors() {
|
|
258
|
+
const fromContent = this.content.excludeActors;
|
|
259
|
+
return Array.isArray(fromContent) ? fromContent.filter((actor) => typeof actor === 'string' && actor !== '') : []
|
|
260
|
+
},
|
|
261
|
+
|
|
251
262
|
resolvedTitle() {
|
|
252
263
|
return this.title || this.content.title || ''
|
|
253
264
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAuditTrailWidget.vue2.js","sources":["../../../../src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tv-if=\"resolvedScope === 'app' || resolvedSource || resolvedEndpoint || (resolvedRegister && resolvedSchema && resolvedObjectId)\"\n\t\tclass=\"cn-audit-trail-widget\">\n\t\t<CnAuditTrailCard\n\t\t\t:source=\"resolvedSource\"\n\t\t\t:endpoint=\"resolvedEndpoint\"\n\t\t\t:register=\"resolvedRegister\"\n\t\t\t:schema=\"resolvedSchema\"\n\t\t\t:objectId=\"resolvedObjectId\"\n\t\t\t:scope=\"resolvedScope\"\n\t\t\t:title=\"resolvedTitle\"\n\t\t\t:maxDisplay=\"resolvedMaxDisplay\"\n\t\t\t:layout=\"content && typeof content.layout === 'string' ? content.layout : ''\"\n\t\t\t:excludeActions=\"resolvedExcludeActions\"\n\t\t\t:actionLabels=\"actionLabels\"\n\t\t\t:valueLabels=\"valueLabels\"\n\t\t\t:changeLabels=\"changeLabels\"\n\t\t\t:object=\"ctx.object || ctx.objectData || null\"\n\t\t\t:relatedSources=\"relatedSources\"\n\t\t\t:footnote=\"footnote\"\n\t\t\tv-bind=\"emptyText ? { noEntriesLabel: emptyText } : {}\" />\n\t</div>\n</template>\n\n<script>\nimport CnAuditTrailCard from '../CnAuditTrailCard/CnAuditTrailCard.vue'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\n\n/**\n * CnAuditTrailWidget — thin built-in widget wrapping CnAuditTrailCard with\n * unified object-context resolution (`audit-trail` widget key, Wave 1 of\n * nextcloud-vue#91).\n *\n * CnAuditTrailCard needs explicit `register` / `schema` / `objectId` props,\n * but the detail render paths surface the current object differently:\n * CnDetailPage's config grid provides a `cnObjectContext` inject, while\n * CnPageRenderer's slot CnWidgetGrid spreads the detail object context as\n * props, and CnDashboardPage's registry branch hands a stored `content`\n * blob. This widget reads whichever is present — explicit props win, then\n * the injects, then `content` — so the single `audit-trail` key works on\n * every surface. It replaces the three identical per-app adapters\n * (procest / zaakafhandelapp / scholiq).\n *\n * Registered in BOTH the v2 grid's BUILT_IN_WIDGETS and (detail-page\n * surface, like the `data` widget) the shared dashboardWidgetRegistry —\n * see `dashboardRegistration.js`.\n */\nexport default {\n\tname: 'CnAuditTrailWidget',\n\n\tcomponents: { CnAuditTrailCard },\n\n\tinject: {\n\t\t/** The host app's translate function, for `content.emptyText`. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/**\n\t\t * Detail-page object context (`{ objectId, object, register, schema }`)\n\t\t * provided by CnDetailPage (raw object or `{ value }` holder).\n\t\t */\n\t\tcnObjectContext: { default: null },\n\t\t/**\n\t\t * Detail object context holder (`{ value: { objectData, schema,\n\t\t * objectType, objectId, register, store } | null }`) provided by\n\t\t * CnPageRenderer for the v2 slot grid.\n\t\t */\n\t\tcnDetailObjectContext: { default: null },\n\t},\n\n\tprops: {\n\t\t/** OpenRegister register slug/id — object context spread as props by CnWidgetGrid (slot path). */\n\t\tregister: { type: String, default: '' },\n\t\t/**\n\t\t * OpenRegister schema — a slug string, or the schema OBJECT the\n\t\t * detail-context merge supplies (its slug/name/id is used).\n\t\t *\n\t\t * @type {string|object}\n\t\t */\n\t\tschema: { type: [String, Object], default: '' },\n\t\t/** The audited object's id — object context spread as props by CnWidgetGrid (slot path). */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** Optional card title override (defaults to the card's translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Maximum audit rows to render (0 falls back to the card default). */\n\t\tmaxDisplay: { type: Number, default: 0 },\n\t\t/**\n\t\t * `app` lists the app-wide feed (every object the caller may read,\n\t\t * narrowed to `register` / `schema` when set) and needs no object;\n\t\t * `object` (the default) is one object's trail. Also read from\n\t\t * `content.scope`.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t */\n\t\tscope: { type: String, default: '' },\n\t\t/** Read the trail of something that is not an object (`{ kind: 'flow-task', id? }`); also read from `content.source`. */\n\t\tsource: { type: Object, default: null },\n\t\t/** A trail URL of its own; also read from `content.endpoint`. */\n\t\tendpoint: { type: String, default: '' },\n\t\t/** Actions to leave out (`['read']`); also read from `content.excludeActions`. */\n\t\texcludeActions: { type: Array, default: () => [] },\n\t\t/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, footnote? }`. */\n\t\t/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, valueLabels? }`. */\n\t\t/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, valueLabels?, relatedSources? }`. */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The resolved object-context bag from either inject shape, or {}.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tctx() {\n\t\t\tconst inj = this.cnObjectContext && (this.cnObjectContext.value || this.cnObjectContext)\n\t\t\tconst holder = this.cnDetailObjectContext && this.cnDetailObjectContext.value\n\t\t\treturn inj || holder || {}\n\t\t},\n\n\t\t/**\n\t\t * The audited object's id: explicit prop → inject context → content.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedObjectId() {\n\t\t\treturn this.objectId || this.ctx.objectId || this.content.objectId || ''\n\t\t},\n\n\t\t/**\n\t\t * The register slug/id: explicit prop → inject context → content.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedRegister() {\n\t\t\treturn this.register || this.ctx.register || this.content.register || ''\n\t\t},\n\n\t\t/**\n\t\t * The schema SLUG: explicit prop → inject context → content; a\n\t\t * schema object collapses to its slug/name/id.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedSchema() {\n\t\t\tconst s = this.schema || this.ctx.schema || this.content.schema || ''\n\t\t\treturn typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''\n\t\t},\n\n\t\t/**\n\t\t * The feed scope: explicit prop → content → `object`.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {('object'|'app')}\n\t\t */\n\t\tresolvedScope() {\n\t\t\tconst s = this.scope || this.content.scope\n\t\t\treturn s === 'app' ? 'app' : 'object'\n\t\t},\n\n\t\t/**\n\t\t * The card title: explicit prop → content → '' (card default).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\t/** @return {object|null} The non-object anchor, from the prop or the content. */\n\t\tresolvedSource() {\n\t\t\tconst source = this.source || this.content.source\n\t\t\treturn source && typeof source === 'object' ? source : null\n\t\t},\n\n\t\t/** @return {string} The trail URL of its own, from the prop or the content. */\n\t\tresolvedEndpoint() {\n\t\t\treturn this.endpoint || (typeof this.content.endpoint === 'string' ? this.content.endpoint : '')\n\t\t},\n\n\t\t/** @return {string} The empty line the content names, through the host's translate, or ''. */\n\t\t/**\n\t\t * `content.actionLabels`, each label through the app's translate.\n\t\t *\n\t\t * @return {Object<string, string>|null}\n\t\t * @spec openspec/changes/audit-trail-action-labels/specs/audit-trail/spec.md#requirement-a-trail-can-say-what-happened-in-words\n\t\t */\n\t\tactionLabels() {\n\t\t\tconst labels = this.content.actionLabels\n\t\t\tif (!labels || typeof labels !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (text) => text\n\t\t\treturn Object.fromEntries(Object.entries(labels)\n\t\t\t\t.filter(([, text]) => typeof text === 'string' && text !== '')\n\t\t\t\t.map(([key, text]) => [key, translate(text)]))\n\t\t},\n\n\t\t/**\n\t\t * `content.changeLabels`, each rule's label through the app's translate.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tchangeLabels() {\n\t\t\tconst rules = this.content.changeLabels\n\t\t\tif (!Array.isArray(rules)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (text) => text\n\t\t\treturn rules\n\t\t\t\t.filter((rule) => rule && typeof rule.label === 'string' && rule.label !== '')\n\t\t\t\t.map((rule) => ({ ...rule, label: translate(rule.label) }))\n\t\t},\n\n\t\t/**\n\t\t * `content.footnote`, a muted line under the trail with the record's\n\t\t * fields filled in (\"Reference {identifier}\"); '' when a field is empty.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/audit-trail-footnote/specs/audit-trail/spec.md#requirement-a-history-card-can-end-in-a-line-about-the-record\n\t\t */\n\t\tfootnote() {\n\t\t\tconst note = this.content.footnote\n\t\t\tif (typeof note !== 'string' || note === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (text) => text\n\t\t\treturn fillTemplate(translate(note), this.ctx.object || this.ctx.objectData || null)\n\t\t},\n\n\t\t/**\n\t\t * `content.valueLabels`, each word through the app's translate.\n\t\t *\n\t\t * @return {{[key: string]: {[value: string]: string}}|null}\n\t\t * @spec openspec/changes/audit-label-changed-values/specs/audit-trail/spec.md#requirement-a-trail-label-can-quote-what-the-entry-recorded\n\t\t */\n\t\tvalueLabels() {\n\t\t\tconst labels = this.content.valueLabels\n\t\t\tif (!labels || typeof labels !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (text) => text\n\t\t\treturn Object.fromEntries(Object.entries(labels)\n\t\t\t\t.filter(([, words]) => words && typeof words === 'object')\n\t\t\t\t.map(([key, words]) => [key, Object.fromEntries(Object.entries(words)\n\t\t\t\t\t.filter(([, text]) => typeof text === 'string' && text !== '')\n\t\t\t\t\t.map(([value, text]) => [value, translate(text)]))]))\n\t\t},\n\n\t\t/**\n\t\t * `content.relatedSources`: records beside the object whose events\n\t\t * join its history (see CnAuditTrailCard).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\trelatedSources() {\n\t\t\treturn Array.isArray(this.content.relatedSources) ? this.content.relatedSources : []\n\t\t},\n\n\t\temptyText() {\n\t\t\tconst text = this.content.emptyText\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The actions to leave out: explicit prop → content → none.\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-exclude-actions/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-events-by-action\n\t\t * @return {Array<string>}\n\t\t */\n\t\tresolvedExcludeActions() {\n\t\t\tif (this.excludeActions.length > 0) {\n\t\t\t\treturn this.excludeActions\n\t\t\t}\n\t\t\tconst fromContent = this.content.excludeActions\n\t\t\treturn Array.isArray(fromContent) ? fromContent.filter((action) => typeof action === 'string' && action !== '') : []\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\treturn this.title || this.content.title || ''\n\t\t},\n\n\t\t/**\n\t\t * The row cap: explicit prop → content → the card's own default (5).\n\t\t *\n\t\t * @return {number}\n\t\t */\n\t\tresolvedMaxDisplay() {\n\t\t\tif (this.maxDisplay > 0) {\n\t\t\t\treturn this.maxDisplay\n\t\t\t}\n\t\t\tconst fromContent = Number(this.content.maxDisplay)\n\t\t\treturn Number.isFinite(fromContent) && fromContent > 0 ? fromContent : 5\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* The card keeps its own box, footnote included. */\n.cn-audit-trail-widget {\n\tdisplay: contents;\n}\n</style>\n"],"names":["CnAuditTrailCard"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnAuditTrailWidget.vue2.js","sources":["../../../../src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tv-if=\"resolvedScope === 'app' || resolvedSource || resolvedEndpoint || (resolvedRegister && resolvedSchema && resolvedObjectId)\"\n\t\tclass=\"cn-audit-trail-widget\">\n\t\t<CnAuditTrailCard\n\t\t\t:source=\"resolvedSource\"\n\t\t\t:endpoint=\"resolvedEndpoint\"\n\t\t\t:register=\"resolvedRegister\"\n\t\t\t:schema=\"resolvedSchema\"\n\t\t\t:objectId=\"resolvedObjectId\"\n\t\t\t:scope=\"resolvedScope\"\n\t\t\t:title=\"resolvedTitle\"\n\t\t\t:maxDisplay=\"resolvedMaxDisplay\"\n\t\t\t:layout=\"content && typeof content.layout === 'string' ? content.layout : ''\"\n\t\t\t:excludeActions=\"resolvedExcludeActions\"\n\t\t\t:excludeActors=\"resolvedExcludeActors\"\n\t\t\t:actionLabels=\"actionLabels\"\n\t\t\t:valueLabels=\"valueLabels\"\n\t\t\t:changeLabels=\"changeLabels\"\n\t\t\t:object=\"ctx.object || ctx.objectData || null\"\n\t\t\t:relatedSources=\"relatedSources\"\n\t\t\t:footnote=\"footnote\"\n\t\t\tv-bind=\"emptyText ? { noEntriesLabel: emptyText } : {}\" />\n\t</div>\n</template>\n\n<script>\nimport CnAuditTrailCard from '../CnAuditTrailCard/CnAuditTrailCard.vue'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\n\n/**\n * CnAuditTrailWidget — thin built-in widget wrapping CnAuditTrailCard with\n * unified object-context resolution (`audit-trail` widget key, Wave 1 of\n * nextcloud-vue#91).\n *\n * CnAuditTrailCard needs explicit `register` / `schema` / `objectId` props,\n * but the detail render paths surface the current object differently:\n * CnDetailPage's config grid provides a `cnObjectContext` inject, while\n * CnPageRenderer's slot CnWidgetGrid spreads the detail object context as\n * props, and CnDashboardPage's registry branch hands a stored `content`\n * blob. This widget reads whichever is present — explicit props win, then\n * the injects, then `content` — so the single `audit-trail` key works on\n * every surface. It replaces the three identical per-app adapters\n * (procest / zaakafhandelapp / scholiq).\n *\n * Registered in BOTH the v2 grid's BUILT_IN_WIDGETS and (detail-page\n * surface, like the `data` widget) the shared dashboardWidgetRegistry —\n * see `dashboardRegistration.js`.\n */\nexport default {\n\tname: 'CnAuditTrailWidget',\n\n\tcomponents: { CnAuditTrailCard },\n\n\tinject: {\n\t\t/** The host app's translate function, for `content.emptyText`. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/**\n\t\t * Detail-page object context (`{ objectId, object, register, schema }`)\n\t\t * provided by CnDetailPage (raw object or `{ value }` holder).\n\t\t */\n\t\tcnObjectContext: { default: null },\n\t\t/**\n\t\t * Detail object context holder (`{ value: { objectData, schema,\n\t\t * objectType, objectId, register, store } | null }`) provided by\n\t\t * CnPageRenderer for the v2 slot grid.\n\t\t */\n\t\tcnDetailObjectContext: { default: null },\n\t},\n\n\tprops: {\n\t\t/** OpenRegister register slug/id — object context spread as props by CnWidgetGrid (slot path). */\n\t\tregister: { type: String, default: '' },\n\t\t/**\n\t\t * OpenRegister schema — a slug string, or the schema OBJECT the\n\t\t * detail-context merge supplies (its slug/name/id is used).\n\t\t *\n\t\t * @type {string|object}\n\t\t */\n\t\tschema: { type: [String, Object], default: '' },\n\t\t/** The audited object's id — object context spread as props by CnWidgetGrid (slot path). */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** Optional card title override (defaults to the card's translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Maximum audit rows to render (0 falls back to the card default). */\n\t\tmaxDisplay: { type: Number, default: 0 },\n\t\t/**\n\t\t * `app` lists the app-wide feed (every object the caller may read,\n\t\t * narrowed to `register` / `schema` when set) and needs no object;\n\t\t * `object` (the default) is one object's trail. Also read from\n\t\t * `content.scope`.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t */\n\t\tscope: { type: String, default: '' },\n\t\t/** Read the trail of something that is not an object (`{ kind: 'flow-task', id? }`); also read from `content.source`. */\n\t\tsource: { type: Object, default: null },\n\t\t/** A trail URL of its own; also read from `content.endpoint`. */\n\t\tendpoint: { type: String, default: '' },\n\t\t/** Actions to leave out (`['read']`); also read from `content.excludeActions`. */\n\t\texcludeActions: { type: Array, default: () => [] },\n\t\t/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, footnote? }`. */\n\t\t/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, valueLabels? }`. */\n\t\t/** Stored widget content blob (CnDashboardPage registry branch): `{ title, maxDisplay, register?, schema?, objectId?, source?, endpoint?, emptyText?, excludeActions?, actionLabels?, valueLabels?, relatedSources?, excludeActors? }`. */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The resolved object-context bag from either inject shape, or {}.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tctx() {\n\t\t\tconst inj = this.cnObjectContext && (this.cnObjectContext.value || this.cnObjectContext)\n\t\t\tconst holder = this.cnDetailObjectContext && this.cnDetailObjectContext.value\n\t\t\treturn inj || holder || {}\n\t\t},\n\n\t\t/**\n\t\t * The audited object's id: explicit prop → inject context → content.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedObjectId() {\n\t\t\treturn this.objectId || this.ctx.objectId || this.content.objectId || ''\n\t\t},\n\n\t\t/**\n\t\t * The register slug/id: explicit prop → inject context → content.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedRegister() {\n\t\t\treturn this.register || this.ctx.register || this.content.register || ''\n\t\t},\n\n\t\t/**\n\t\t * The schema SLUG: explicit prop → inject context → content; a\n\t\t * schema object collapses to its slug/name/id.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedSchema() {\n\t\t\tconst s = this.schema || this.ctx.schema || this.content.schema || ''\n\t\t\treturn typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''\n\t\t},\n\n\t\t/**\n\t\t * The feed scope: explicit prop → content → `object`.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-audit-trail-widget-reads-the-app-wide-feed\n\t\t * @return {('object'|'app')}\n\t\t */\n\t\tresolvedScope() {\n\t\t\tconst s = this.scope || this.content.scope\n\t\t\treturn s === 'app' ? 'app' : 'object'\n\t\t},\n\n\t\t/**\n\t\t * The card title: explicit prop → content → '' (card default).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\t/** @return {object|null} The non-object anchor, from the prop or the content. */\n\t\tresolvedSource() {\n\t\t\tconst source = this.source || this.content.source\n\t\t\treturn source && typeof source === 'object' ? source : null\n\t\t},\n\n\t\t/** @return {string} The trail URL of its own, from the prop or the content. */\n\t\tresolvedEndpoint() {\n\t\t\treturn this.endpoint || (typeof this.content.endpoint === 'string' ? this.content.endpoint : '')\n\t\t},\n\n\t\t/** @return {string} The empty line the content names, through the host's translate, or ''. */\n\t\t/**\n\t\t * `content.actionLabels`, each label through the app's translate.\n\t\t *\n\t\t * @return {Object<string, string>|null}\n\t\t * @spec openspec/changes/audit-trail-action-labels/specs/audit-trail/spec.md#requirement-a-trail-can-say-what-happened-in-words\n\t\t */\n\t\tactionLabels() {\n\t\t\tconst labels = this.content.actionLabels\n\t\t\tif (!labels || typeof labels !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (text) => text\n\t\t\treturn Object.fromEntries(Object.entries(labels)\n\t\t\t\t.filter(([, text]) => typeof text === 'string' && text !== '')\n\t\t\t\t.map(([key, text]) => [key, translate(text)]))\n\t\t},\n\n\t\t/**\n\t\t * `content.changeLabels`, each rule's label through the app's translate.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tchangeLabels() {\n\t\t\tconst rules = this.content.changeLabels\n\t\t\tif (!Array.isArray(rules)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (text) => text\n\t\t\treturn rules\n\t\t\t\t.filter((rule) => rule && typeof rule.label === 'string' && rule.label !== '')\n\t\t\t\t.map((rule) => ({ ...rule, label: translate(rule.label) }))\n\t\t},\n\n\t\t/**\n\t\t * `content.footnote`, a muted line under the trail with the record's\n\t\t * fields filled in (\"Reference {identifier}\"); '' when a field is empty.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/audit-trail-footnote/specs/audit-trail/spec.md#requirement-a-history-card-can-end-in-a-line-about-the-record\n\t\t */\n\t\tfootnote() {\n\t\t\tconst note = this.content.footnote\n\t\t\tif (typeof note !== 'string' || note === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (text) => text\n\t\t\treturn fillTemplate(translate(note), this.ctx.object || this.ctx.objectData || null)\n\t\t},\n\n\t\t/**\n\t\t * `content.valueLabels`, each word through the app's translate.\n\t\t *\n\t\t * @return {{[key: string]: {[value: string]: string}}|null}\n\t\t * @spec openspec/changes/audit-label-changed-values/specs/audit-trail/spec.md#requirement-a-trail-label-can-quote-what-the-entry-recorded\n\t\t */\n\t\tvalueLabels() {\n\t\t\tconst labels = this.content.valueLabels\n\t\t\tif (!labels || typeof labels !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (text) => text\n\t\t\treturn Object.fromEntries(Object.entries(labels)\n\t\t\t\t.filter(([, words]) => words && typeof words === 'object')\n\t\t\t\t.map(([key, words]) => [key, Object.fromEntries(Object.entries(words)\n\t\t\t\t\t.filter(([, text]) => typeof text === 'string' && text !== '')\n\t\t\t\t\t.map(([value, text]) => [value, translate(text)]))]))\n\t\t},\n\n\t\t/**\n\t\t * `content.relatedSources`: records beside the object whose events\n\t\t * join its history (see CnAuditTrailCard).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t * @spec openspec/changes/audit-trail-related-sources/specs/audit-trail/spec.md#requirement-an-objects-history-can-include-the-events-of-records-beside-it\n\t\t */\n\t\trelatedSources() {\n\t\t\treturn Array.isArray(this.content.relatedSources) ? this.content.relatedSources : []\n\t\t},\n\n\t\temptyText() {\n\t\t\tconst text = this.content.emptyText\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The actions to leave out: explicit prop → content → none.\n\t\t *\n\t\t * @spec openspec/changes/audit-trail-exclude-actions/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-events-by-action\n\t\t * @return {Array<string>}\n\t\t */\n\t\tresolvedExcludeActions() {\n\t\t\tif (this.excludeActions.length > 0) {\n\t\t\t\treturn this.excludeActions\n\t\t\t}\n\t\t\tconst fromContent = this.content.excludeActions\n\t\t\treturn Array.isArray(fromContent) ? fromContent.filter((action) => typeof action === 'string' && action !== '') : []\n\t\t},\n\n\t\t/**\n\t\t * The actors to leave out, from `content.excludeActors`.\n\t\t *\n\t\t * @spec openspec/changes/audit-card-exclude-actors/specs/audit-trail/spec.md#requirement-a-history-card-can-leave-out-entries-by-actor\n\t\t * @return {Array<string>}\n\t\t */\n\t\tresolvedExcludeActors() {\n\t\t\tconst fromContent = this.content.excludeActors\n\t\t\treturn Array.isArray(fromContent) ? fromContent.filter((actor) => typeof actor === 'string' && actor !== '') : []\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\treturn this.title || this.content.title || ''\n\t\t},\n\n\t\t/**\n\t\t * The row cap: explicit prop → content → the card's own default (5).\n\t\t *\n\t\t * @return {number}\n\t\t */\n\t\tresolvedMaxDisplay() {\n\t\t\tif (this.maxDisplay > 0) {\n\t\t\t\treturn this.maxDisplay\n\t\t\t}\n\t\t\tconst fromContent = Number(this.content.maxDisplay)\n\t\t\treturn Number.isFinite(fromContent) && fromContent > 0 ? fromContent : 5\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* The card keeps its own box, footnote included. */\n.cn-audit-trail-widget {\n\tdisplay: contents;\n}\n</style>\n"],"names":["CnAuditTrailCard"],"mappings":"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"}
|
|
@@ -21,13 +21,14 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
21
21
|
maxDisplay: $options.resolvedMaxDisplay,
|
|
22
22
|
layout: $props.content && typeof $props.content.layout === 'string' ? $props.content.layout : '',
|
|
23
23
|
excludeActions: $options.resolvedExcludeActions,
|
|
24
|
+
excludeActors: $options.resolvedExcludeActors,
|
|
24
25
|
actionLabels: $options.actionLabels,
|
|
25
26
|
valueLabels: $options.valueLabels,
|
|
26
27
|
changeLabels: $options.changeLabels,
|
|
27
28
|
object: $options.ctx.object || $options.ctx.objectData || null,
|
|
28
29
|
relatedSources: $options.relatedSources,
|
|
29
30
|
footnote: $options.footnote
|
|
30
|
-
}, $options.emptyText ? { noEntriesLabel: $options.emptyText } : {}), null, 16 /* FULL_PROPS */, ["source", "endpoint", "register", "schema", "objectId", "scope", "title", "maxDisplay", "layout", "excludeActions", "actionLabels", "valueLabels", "changeLabels", "object", "relatedSources", "footnote"])
|
|
31
|
+
}, $options.emptyText ? { noEntriesLabel: $options.emptyText } : {}), null, 16 /* FULL_PROPS */, ["source", "endpoint", "register", "schema", "objectId", "scope", "title", "maxDisplay", "layout", "excludeActions", "excludeActors", "actionLabels", "valueLabels", "changeLabels", "object", "relatedSources", "footnote"])
|
|
31
32
|
]))
|
|
32
33
|
: createCommentVNode("v-if", true)
|
|
33
34
|
}
|