@conduction/nextcloud-vue 2.149.0 → 2.151.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/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +7 -2
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +40 -41
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +12 -0
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +6 -3
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +13 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +5 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +46 -0
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +64 -64
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +15 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue.js +1 -1
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue2.js.map +1 -1
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js +16 -5
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +25 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +82 -68
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/eventStatus.js +43 -2
- package/dist/esm/integrations/builtin/calendar/eventStatus.js.map +1 -1
- package/dist/esm/l10n/en.json.js +4 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +5 -2
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +707 -438
- package/dist/esm/utils/fillTemplate.js +19 -2
- package/dist/esm/utils/fillTemplate.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +926 -723
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +707 -438
- package/l10n/en.json +4 -1
- package/l10n/nl.json +5 -2
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +17 -4
- package/src/components/CnChartWidget/CnChartWidget.md +1 -1
- package/src/components/CnChartWidget/CnChartWidget.vue +12 -0
- package/src/components/CnConversationThread/CnConversationThread.vue +16 -2
- package/src/components/CnConversationThread/CnConversationWidget.vue +5 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +47 -2
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +15 -1
- package/src/components/CnPlanWidget/CnPlanWidgetRow.vue +17 -2
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +45 -2
- package/src/components/CnRetentionWidget/CnRetentionWidget.vue +8 -1
- package/src/components/CnTimelineWidget/CnTimelineManage.vue +1 -1
- package/src/css/board.css +2 -0
- package/src/css/dialog.css +6 -0
- package/src/css/look-board-detail.css +137 -0
- package/src/css/look-board-index.css +5 -1
- package/src/css/look-board.css +78 -2
- package/src/integrations/builtin/calendar/eventStatus.js +42 -1
- package/src/utils/fillTemplate.js +19 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnTimelineManage.vue2.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineManage.vue"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n\n CnTimelineManage — the `manage` mode of CnTimelineWidget: one chronological\n read of OpenRegister's timeline on an object (notes, calls, messages), newest\n first with pinned entries on top, plus what a reader who may manage it can do\n there: filter by kind and visibility, pin, close a follow-up, write a note\n (optionally from a standard text block, optionally visible outside), export\n the shown entries as CSV, and run configured entry actions such as a reply\n dialog.\n\n The list read is filtered by OpenRegister whether or not a filter is asked\n for; the response says whether the reader may manage (`canManage`), and the\n controls are drawn from that rather than guessed. A failed read is not an\n empty history.\n-->\n<template>\n\t<div class=\"cn-timeline-manage\"\n\t\t:class=\"{ 'cn-timeline-manage--composer-only': composerOnly }\"\n\t\tdata-testid=\"cn-timeline-manage\">\n\t\t<template v-if=\"!composerOnly\">\n\t\t\t<div class=\"cn-timeline-manage__header\">\n\t\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t\t{{ titleText }}\n\t\t\t\t\t</h3>\n\t\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t\t{{ subtitleText }}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-timeline-manage__header-actions\">\n\t\t\t\t\t<NcButton v-if=\"canManage && (composerEnabled || composerSeparate)\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-add-note\"\n\t\t\t\t\t\t@click=\"focusComposer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Add note') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcButton data-testid=\"cn-timeline-export\" @click=\"exportEntries\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Export') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"cn-timeline-manage__chips\"\n\t\t\t\trole=\"group\"\n\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Kind')\"\n\t\t\t\tdata-testid=\"cn-timeline-kind-filter\">\n\t\t\t\t<button v-for=\"chip in kindChips\"\n\t\t\t\t\t:key=\"chip.key\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-timeline-manage__chip\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-manage__chip--active': chip.active }\"\n\t\t\t\t\t:aria-pressed=\"chip.active ? 'true' : 'false'\"\n\t\t\t\t\t:data-testid=\"'cn-timeline-chip-' + chip.key\"\n\t\t\t\t\t@click=\"chooseKind(chip.id)\">\n\t\t\t\t\t{{ chip.label }}\n\t\t\t\t\t<span class=\"cn-timeline-manage__chip-count\">{{ chip.count }}</span>\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<div class=\"cn-timeline-manage__controls\">\n\t\t\t\t<NcSelect v-if=\"canManage\"\n\t\t\t\t\tv-model=\"visibilityFilter\"\n\t\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t\t:options=\"visibilityOptions\"\n\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t:inputLabel=\"visibilityLabelShown ? t('nextcloud-vue', 'Visibility') : undefined\"\n\t\t\t\t\t:labelOutside=\"!visibilityLabelShown\"\n\t\t\t\t\t:ariaLabelCombobox=\"t('nextcloud-vue', 'Visibility')\"\n\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Internal and public')\"\n\t\t\t\t\tdata-testid=\"cn-timeline-visibility-filter\"\n\t\t\t\t\t@update:modelValue=\"load\" />\n\t\t\t</div>\n\n\t\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\n\t\t\t<NcNoteCard v-else-if=\"error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t\t{{ error }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<NcEmptyContent v-else-if=\"entries.length === 0\"\n\t\t\t\t:name=\"t('nextcloud-vue', 'Nothing recorded yet')\"\n\t\t\t\t:description=\"t('nextcloud-vue', 'Notes, calls and messages appear here in the order they happened.')\"\n\t\t\t\tdata-testid=\"cn-timeline-empty\" />\n\n\t\t\t<ul v-else class=\"cn-timeline-manage__list\" data-testid=\"cn-timeline-list\">\n\t\t\t\t<li v-for=\"entry in entries\"\n\t\t\t\t\t:key=\"entry.id\"\n\t\t\t\t\tclass=\"cn-timeline-manage__entry\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-manage__entry--pinned': entry.pinned }\"\n\t\t\t\t\t:data-kind=\"entry.kind || 'note'\"\n\t\t\t\t\tdata-testid=\"cn-timeline-entry\">\n\t\t\t\t\t<div class=\"cn-timeline-manage__head\">\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__kind\">{{ kindLabel(entry) }}</span>\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__author\">{{ entry.author }}</span>\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__moment\">{{ moment(entry.created) }}</span>\n\t\t\t\t\t\t<span v-if=\"entry.visibility === 'public'\"\n\t\t\t\t\t\t\tclass=\"cn-timeline-manage__badge\"\n\t\t\t\t\t\t\tdata-testid=\"cn-timeline-public\">\n\t\t\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\t\tclass=\"cn-timeline-manage__badge cn-timeline-manage__badge--open\"\n\t\t\t\t\t\t\tdata-testid=\"cn-timeline-followup-open\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Needs an answer') }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<p class=\"cn-timeline-manage__message\">\n\t\t\t\t\t\t{{ entry.message }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<p v-if=\"entry.siblings && entry.siblings.length\"\n\t\t\t\t\t\tclass=\"cn-timeline-manage__siblings\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-siblings\">\n\t\t\t\t\t\t{{ n('nextcloud-vue', 'Also written on %n other record', 'Also written on %n other records', entry.siblings.length) }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<div v-if=\"canManage && !entry.isRead\" class=\"cn-timeline-manage__actions\">\n\t\t\t\t\t\t<NcButton variant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-pin-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"togglePin(entry)\">\n\t\t\t\t\t\t\t{{ entry.pinned ? t('nextcloud-vue', 'Unpin') : t('nextcloud-vue', 'Pin') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton v-for=\"action in actionsFor(entry)\"\n\t\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-action-' + action.id + '-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"openAction(action, entry)\">\n\t\t\t\t\t\t\t{{ translate(action.label) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-followup-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"closeFollowUp(entry)\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Mark as answered') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\n\t\t\t<div v-if=\"(!loading && !error && allEntries.length > 0) || auditTrailLinkLabel || readsToggleLabel\"\n\t\t\t\tclass=\"cn-timeline-manage__footer\">\n\t\t\t\t<p v-if=\"!loading && !error && allEntries.length > 0\"\n\t\t\t\t\tclass=\"cn-timeline-manage__count\"\n\t\t\t\t\tdata-testid=\"cn-timeline-count\">\n\t\t\t\t\t{{ countLine }}\n\t\t\t\t</p>\n\t\t\t\t<NcCheckboxRadioSwitch v-if=\"readsToggleLabel && readsAllowed\"\n\t\t\t\t\tv-model=\"includeReads\"\n\t\t\t\t\tdata-testid=\"cn-timeline-include-reads\"\n\t\t\t\t\t@update:modelValue=\"load\">\n\t\t\t\t\t{{ readsToggleLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<NcButton v-if=\"auditTrailLinkLabel\"\n\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\tclass=\"cn-timeline-manage__audit-link\"\n\t\t\t\t\tdata-testid=\"cn-timeline-audit-link\"\n\t\t\t\t\t@click=\"openAuditTrail\">\n\t\t\t\t\t{{ auditTrailLinkLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<div v-if=\"composerOnly && canManage && composerEnabled\"\n\t\t\tclass=\"cn-timeline-manage__header\"\n\t\t\tdata-testid=\"cn-timeline-composer-heading\">\n\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t{{ composerTitleText }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t{{ composerSubtitleText }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-if=\"composerOnly && error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<form v-if=\"canManage && composerEnabled\"\n\t\t\tref=\"composer\"\n\t\t\tclass=\"cn-timeline-manage__composer\"\n\t\t\tdata-testid=\"cn-timeline-composer\"\n\t\t\t@submit.prevent=\"submit\">\n\t\t\t<template v-if=\"!composerOnly\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__composer-title\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add note') }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__composer-hint\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible') }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t\t<label v-if=\"textBlocks.length\" class=\"cn-timeline-manage__draft-label\" :for=\"blockId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Template') }}\n\t\t\t</label>\n\t\t\t<NcSelect v-if=\"textBlocks.length\"\n\t\t\t\tv-model=\"chosenBlock\"\n\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t:options=\"blockOptions\"\n\t\t\t\t:clearable=\"true\"\n\t\t\t\tlabel=\"label\"\n\t\t\t\t:inputId=\"blockId\"\n\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t:ariaLabelCombobox=\"t('nextcloud-vue', 'Template')\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write your own')\"\n\t\t\t\tdata-testid=\"cn-timeline-block\"\n\t\t\t\t@update:modelValue=\"pickBlock\" />\n\n\t\t\t<label class=\"cn-timeline-manage__draft-label\" :for=\"draftId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Note') }}\n\t\t\t</label>\n\t\t\t<textarea :id=\"draftId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-timeline-manage__draft\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write a note on this record')\"\n\t\t\t\tdata-testid=\"cn-timeline-draft\" />\n\n\t\t\t<div class=\"cn-timeline-manage__composer-foot\">\n\t\t\t\t<NcCheckboxRadioSwitch v-model=\"draftIsPublic\" data-testid=\"cn-timeline-draft-public\">\n\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t\t<NcButton variant=\"primary\"\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t:disabled=\"saving || !draft.trim()\"\n\t\t\t\t\tdata-testid=\"cn-timeline-save\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add it to the timeline') }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</form>\n\n\t\t<component :is=\"activeModal.component\"\n\t\t\tv-if=\"activeModal\"\n\t\t\tv-bind=\"activeModal.props\"\n\t\t\tv-on=\"activeModal.listeners\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport { prefixUrl } from '../../utils/headers.js'\n\nlet instanceCount = 0\n\n/** The kind of a read row (`readsToggle`), never a kind OpenRegister declares. */\nconst READ_KIND = 'cn-read'\n\n/** Event-bus channel: a note was added to an object's timeline (`{ objectId, source }`). */\nconst TIMELINE_CHANGED = 'cn:timeline:changed'\n\n/** Event-bus channel: the list's \"Add note\" asks the separate form card to take focus (`{ objectId }`). */\nconst TIMELINE_COMPOSE = 'cn:timeline:compose'\n\n/**\n * Read a dotted path off a value.\n *\n * @param {object} value The value.\n * @param {string} path The path.\n * @return {unknown} What is there, or undefined.\n */\nfunction readPath(value, path) {\n\treturn String(path).split('.').reduce((at, key) => (at === null || at === undefined ? undefined : at[key]), value)\n}\n\nexport default {\n\tname: 'CnTimelineManage',\n\n\tcomponents: { Download, NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect, Plus },\n\n\tinject: {\n\t\t/** The app's component registry; entry actions resolve their modal here. */\n\t\tcnRegistry: { default: () => ({}) },\n\t\t/** Consumer translation function; manifest labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's object sidebar channel; the audit trail link opens its tab. */\n\t\tobjectSidebarState: { default: null },\n\t},\n\n\tprops: {\n\t\t/** Register slug. */\n\t\tregister: { type: String, default: '' },\n\t\t/** Schema slug. */\n\t\tschema: { type: String, default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/**\n\t\t * The widget content: `{ title?, subtitle?, publicLabel?, exportName?,\n\t\t * composer?, textBlocks?, entryActions?, auditTrailLink? }`.\n\t\t * `composer`: `true` (default) draws the note form under the list,\n\t\t * `false` none, `\"separate\"` none but keeps the \"Add note\" button,\n\t\t * which brings a `\"only\"` instance (the form alone, a card of its own\n\t\t * in a stack) into view; a note saved there reloads the list.\n\t\t * `readsToggle` (`true` or a label) adds a footer switch, off by\n\t\t * default, that puts who read the record (its audit trail's reads)\n\t\t * among the entries; the count then says \"changes only\" while it is off.\n\t\t * `auditTrailLink` (`true` or a label) draws a footer link that opens\n\t\t * the object sidebar on its audit trail tab, `auditTrailTab` when the\n\t\t * page declares that tab under its own id.\n\t\t */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t},\n\n\tdata() {\n\t\tinstanceCount += 1\n\t\treturn {\n\t\t\tuid: instanceCount,\n\t\t\tallEntries: [],\n\t\t\tentries: [],\n\t\t\tkinds: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tcanManage: false,\n\t\t\tkindFilter: null,\n\t\t\tvisibilityFilter: null,\n\t\t\ttextBlocks: [],\n\t\t\tchosenBlock: null,\n\t\t\tdraft: '',\n\t\t\tdraftIsPublic: false,\n\t\t\tsaving: false,\n\t\t\tactiveModal: null,\n\t\t\t/** Whether the list also shows who read the record (`readsToggle`). */\n\t\t\tincludeReads: false,\n\t\t\t/** Whether OpenRegister gives this reader read entries (`readEventsVisible`); null until asked. */\n\t\t\treadsAllowed: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\ttitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'History')\n\t\t},\n\n\t\tsubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'What happened, who did it and when, newest first')\n\t\t},\n\n\t\t/** @return {string} The title of the note form's own card (`composer: \"only\"`): `content.title`, else Add note. */\n\t\tcomposerTitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'Add note')\n\t\t},\n\n\t\t/** @return {string} The line under that title: `content.subtitle`, else where the note goes. */\n\t\tcomposerSubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible')\n\t\t},\n\n\t\tpublicLabel() {\n\t\t\treturn this.content.publicLabel ? this.translate(this.content.publicLabel) : t('nextcloud-vue', 'Visible to the requester')\n\t\t},\n\n\t\t/**\n\t\t * The audit trail link's words, or '' when it is not drawn.\n\t\t *\n\t\t * @spec openspec/changes/timeline-audit-trail-link/specs/timeline/spec.md#requirement-the-manage-timeline-can-point-at-the-audit-trail-in-the-sidebar\n\t\t * @return {string}\n\t\t */\n\t\tauditTrailLinkLabel() {\n\t\t\tconst link = this.content.auditTrailLink\n\t\t\tif (!link || !this.objectSidebarState) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof link === 'string' ? this.translate(link) : t('nextcloud-vue', 'Full audit trail in the sidebar')\n\t\t},\n\n\t\t/**\n\t\t * Whether this instance draws the note form: inline (`composer` true or\n\t\t * unset) or as the whole widget (`\"only\"`).\n\t\t *\n\t\t * @spec openspec/changes/timeline-composer-card/specs/timeline/spec.md#requirement-the-note-form-can-be-its-own-card\n\t\t * @return {boolean}\n\t\t */\n\t\tcomposerEnabled() {\n\t\t\treturn this.content.composer !== false && this.content.composer !== 'separate'\n\t\t},\n\n\t\t/**\n\t\t * The words of the \"also who read it\" switch, or '' when the widget\n\t\t * does not offer it (`readsToggle`: true or a label).\n\t\t *\n\t\t * @spec openspec/changes/timeline-reads-toggle/specs/timeline/spec.md#requirement-the-history-can-show-who-read-the-record\n\t\t * @return {string}\n\t\t */\n\t\treadsToggleLabel() {\n\t\t\tconst toggle = this.content.readsToggle\n\t\t\tif (!toggle) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof toggle === 'string' ? this.translate(toggle) : t('nextcloud-vue', 'Also who read it')\n\t\t},\n\n\t\t/**\n\t\t * \"3 of 10 events\", and \", changes only\" while reads can be shown but are not.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tcountLine() {\n\t\t\tconst values = { shown: this.entries.length, total: this.allEntries.length }\n\t\t\treturn this.readsToggleLabel && this.readsAllowed && !this.includeReads\n\t\t\t\t? t('nextcloud-vue', '{shown} of {total} events, changes only', values)\n\t\t\t\t: t('nextcloud-vue', '{shown} of {total} events', values)\n\t\t},\n\n\t\t/**\n\t\t * Whether the visibility filter shows its \"Visibility\" label. With\n\t\t * `visibilityLabel: false` it keeps only its accessible name and the\n\t\t * select reads \"Internal and public\" on its own (board DqZaakHistorie).\n\t\t *\n\t\t * @spec openspec/changes/timeline-visibility-filter-unlabelled/specs/timeline/spec.md#requirement-the-visibility-filter-can-go-without-a-visible-label\n\t\t * @return {boolean}\n\t\t */\n\t\tvisibilityLabelShown() {\n\t\t\treturn this.content.visibilityLabel !== false\n\t\t},\n\n\t\t/** @return {boolean} The widget is the note form alone (`composer: \"only\"`), a card of its own beside the list. */\n\t\tcomposerOnly() {\n\t\t\treturn this.content.composer === 'only'\n\t\t},\n\n\t\t/** @return {boolean} The list draws no form; its \"Add note\" brings the separate form card into view (`composer: \"separate\"`). */\n\t\tcomposerSeparate() {\n\t\t\treturn this.content.composer === 'separate'\n\t\t},\n\n\t\tdraftId() {\n\t\t\treturn `cn-timeline-draft-${this.uid}`\n\t\t},\n\n\t\tblockId() {\n\t\t\treturn `cn-timeline-block-${this.uid}`\n\t\t},\n\n\t\t/**\n\t\t * The kind options, the plain note first. A note is an entry with NO\n\t\t * kind, so \"Note\" filters on its absence.\n\t\t *\n\t\t * @return {Array<object>} The options.\n\t\t */\n\t\tkindOptions() {\n\t\t\tconst options = [{ id: '', label: t('nextcloud-vue', 'Note') }].concat(this.kinds.map((kind) => ({ id: kind.slug, label: kind.title || kind.slug })))\n\t\t\treturn this.includeReads ? options.concat([{ id: READ_KIND, label: t('nextcloud-vue', 'Viewed') }]) : options\n\t\t},\n\n\t\t/**\n\t\t * All, then every kind the object has entries of, each with its count.\n\t\t *\n\t\t * @spec openspec/changes/timeline-all-chip-host-label/specs/timeline/spec.md#requirement-the-timelines-all-chip-reads-the-hosts-word\n\t\t * @return {Array<object>} The chips.\n\t\t */\n\t\tkindChips() {\n\t\t\tconst chosen = this.kindFilter ? (this.kindFilter.id || '') : null\n\t\t\tconst counts = new Map()\n\t\t\tfor (const entry of this.allEntries) {\n\t\t\t\tconst kind = entry.kind || ''\n\t\t\t\tcounts.set(kind, (counts.get(kind) || 0) + 1)\n\t\t\t}\n\t\t\t// The host's word first, as its own filter chips read (\"Alles\"), then the library's.\n\t\t\tconst hostAll = typeof this.cnTranslate === 'function' ? this.cnTranslate('All') : 'All'\n\t\t\tconst allLabel = typeof hostAll === 'string' && hostAll !== '' && hostAll !== 'All' ? hostAll : t('nextcloud-vue', 'All')\n\t\t\tconst chips = [{ key: 'all', id: null, label: allLabel, count: this.allEntries.length, active: chosen === null }]\n\t\t\tfor (const option of this.kindOptions) {\n\t\t\t\tconst count = counts.get(option.id) || 0\n\t\t\t\tif (count > 0) {\n\t\t\t\t\tchips.push({ key: option.id || 'note', id: option.id, label: option.label, count, active: chosen === option.id })\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn chips\n\t\t},\n\n\t\tblockOptions() {\n\t\t\treturn this.textBlocks.map((block) => ({ id: block.slug, label: block.title || block.slug }))\n\t\t},\n\n\t\tvisibilityOptions() {\n\t\t\treturn [\n\t\t\t\t{ id: 'internal', label: t('nextcloud-vue', 'Internal only') },\n\t\t\t\t{ id: 'public', label: this.publicLabel },\n\t\t\t]\n\t\t},\n\n\t\tbase() {\n\t\t\treturn this.apiBase.replace(/\\/$/, '')\n\t\t},\n\n\t\ttimelineUrl() {\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/timeline`)\n\t\t},\n\n\t\tentryActions() {\n\t\t\treturn Array.isArray(this.content.entryActions) ? this.content.entryActions.filter((action) => action && action.id) : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: 'load',\n\t},\n\n\tcreated() {\n\t\tthis.onTimelineChanged = (payload) => {\n\t\t\tif (!payload || payload.objectId !== this.objectId || payload.source === this.uid || this.composerOnly) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.load()\n\t\t}\n\t\tthis.onComposeRequested = (payload) => {\n\t\t\tif (this.composerOnly && payload && payload.objectId === this.objectId) {\n\t\t\t\tthis.focusComposer()\n\t\t\t}\n\t\t}\n\t\tsubscribe(TIMELINE_CHANGED, this.onTimelineChanged)\n\t\tsubscribe(TIMELINE_COMPOSE, this.onComposeRequested)\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(TIMELINE_CHANGED, this.onTimelineChanged)\n\t\tunsubscribe(TIMELINE_COMPOSE, this.onComposeRequested)\n\t},\n\n\tmounted() {\n\t\tthis.loadKinds()\n\t\tif (this.content.textBlocks !== false) {\n\t\t\tthis.loadTextBlocks()\n\t\t}\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tn,\n\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** Read the declared kinds, so the filter names them as administered. */\n\t\tasync loadKinds() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/kinds`))\n\t\t\t\tthis.kinds = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.kinds = []\n\t\t\t}\n\t\t},\n\n\t\t/** Read the seeded standard notes. */\n\t\tasync loadTextBlocks() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/text-blocks`))\n\t\t\t\tthis.textBlocks = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.textBlocks = []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Note which standard note was picked. The BLOCK is sent, not its body:\n\t\t * OpenRegister fills the object's own values into it on the way in.\n\t\t *\n\t\t * @param {object|null} block The picked option.\n\t\t */\n\t\tpickBlock(block) {\n\t\t\tthis.chosenBlock = block || null\n\t\t\tif (block) {\n\t\t\t\tconst declared = this.textBlocks.find((entry) => entry.slug === block.id)\n\t\t\t\tthis.draft = declared?.title || block.label\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write the drafted note onto this object.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tif (!this.draft.trim() || !this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst payload = { visibility: this.draftIsPublic ? 'public' : 'internal' }\n\t\t\t\tif (this.chosenBlock?.id) {\n\t\t\t\t\tpayload.textBlock = this.chosenBlock.id\n\t\t\t\t} else {\n\t\t\t\t\tpayload.message = this.draft\n\t\t\t\t}\n\t\t\t\tawait axios.post(this.timelineUrl, payload)\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.chosenBlock = null\n\t\t\t\tthis.draftIsPublic = false\n\t\t\t\temit(TIMELINE_CHANGED, { objectId: this.objectId, source: this.uid })\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That note could not be saved.')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the timeline with the visibility filter, if one is set.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst params = {}\n\t\t\t\tif (this.visibilityFilter?.id) {\n\t\t\t\t\tparams.visibility = this.visibilityFilter.id\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(this.timelineUrl, { params })\n\t\t\t\tthis.canManage = response.data?.canManage === true\n\t\t\t\tconst entries = response.data?.results || []\n\t\t\t\tif (this.readsToggleLabel && this.readsAllowed === null) {\n\t\t\t\t\tawait this.readEntries()\n\t\t\t\t}\n\t\t\t\tthis.allEntries = this.readsToggleLabel && this.readsAllowed && this.includeReads ? this.withReads(entries, await this.readEntries()) : entries\n\t\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t\t} catch {\n\t\t\t\tthis.allEntries = []\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'The timeline could not be read. Try again, or ask an administrator to check OpenRegister.')\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 * Who read the record, from its audit trail (`action=read`), as timeline\n\t\t * rows. OpenRegister gives read entries only to the groups named for\n\t\t * them and says so in `readEventsVisible`, which decides whether the\n\t\t * switch is offered at all; a read it refuses or that fails leaves the\n\t\t * reads out and offers no switch.\n\t\t *\n\t\t * @spec openspec/changes/timeline-reads-toggle/specs/timeline/spec.md#requirement-the-history-can-show-who-read-the-record\n\t\t * @return {Promise<Array<object>>} The read rows.\n\t\t */\n\t\tasync readEntries() {\n\t\t\ttry {\n\t\t\t\tconst url = prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails`)\n\t\t\t\tconst response = await axios.get(url, { params: { action: 'read', limit: 50 } })\n\t\t\t\tthis.readsAllowed = response.data?.readEventsVisible === true\n\t\t\t\tif (!this.readsAllowed) {\n\t\t\t\t\treturn []\n\t\t\t\t}\n\t\t\t\tconst list = response.data?.results || []\n\t\t\t\treturn list\n\t\t\t\t\t.filter((entry) => String(entry.action || '').toLowerCase() === 'read')\n\t\t\t\t\t.map((entry) => ({\n\t\t\t\t\t\tid: `read-${entry.id}`,\n\t\t\t\t\t\tkind: READ_KIND,\n\t\t\t\t\t\tisRead: true,\n\t\t\t\t\t\tauthor: entry.actorDisplayName || entry.userName || entry.user || '',\n\t\t\t\t\t\tcreated: entry.created || entry.creationDateTime || '',\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Opened the record'),\n\t\t\t\t\t}))\n\t\t\t} catch {\n\t\t\t\tthis.readsAllowed = false\n\t\t\t\treturn []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The timeline's entries with the reads among them, newest first; the\n\t\t * pinned entries stay on top.\n\t\t *\n\t\t * @param {Array<object>} entries The timeline's entries.\n\t\t * @param {Array<object>} reads The read rows.\n\t\t * @return {Array<object>} The merged list.\n\t\t */\n\t\twithReads(entries, reads) {\n\t\t\tconst time = (entry) => new Date(entry.created || 0).getTime() || 0\n\t\t\tconst pinned = entries.filter((entry) => entry.pinned)\n\t\t\tconst rest = [...entries.filter((entry) => !entry.pinned), ...reads].sort((a, b) => time(b) - time(a))\n\t\t\treturn [...pinned, ...rest]\n\t\t},\n\n\t\t/**\n\t\t * Show one kind, or every kind for `null`, without reading again.\n\t\t *\n\t\t * @param {string|null} id The kind slug, '' for a note, null for all.\n\t\t */\n\t\tchooseKind(id) {\n\t\t\tthis.kindFilter = id === null ? null : { id }\n\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t},\n\n\t\t/**\n\t\t * The kind filter is applied in the reading: the list endpoint does not\n\t\t * read a kind parameter, so sending one would be dropped in silence.\n\t\t *\n\t\t * @param {Array<object>} results The entries as read.\n\t\t * @return {Array<object>} The entries to show.\n\t\t */\n\t\tapplyKindFilter(results) {\n\t\t\tif (!this.kindFilter) {\n\t\t\t\treturn results\n\t\t\t}\n\t\t\tconst wanted = this.kindFilter.id || ''\n\t\t\treturn results.filter((entry) => (entry.kind || '') === wanted)\n\t\t},\n\n\t\t/**\n\t\t * The shown entries as CSV: when, kind, who, visibility and what.\n\t\t *\n\t\t * @return {string} The CSV text.\n\t\t */\n\t\tentriesCsv() {\n\t\t\tconst cell = (value) => `\"${String(value ?? '').replace(/\"/g, '\"\"')}\"`\n\t\t\tconst rows = [[t('nextcloud-vue', 'When'), t('nextcloud-vue', 'Kind'), t('nextcloud-vue', 'Who'), t('nextcloud-vue', 'Visibility'), t('nextcloud-vue', 'Message')]]\n\t\t\tfor (const entry of this.entries) {\n\t\t\t\trows.push([entry.created, this.kindLabel(entry), entry.author, entry.visibility, entry.message])\n\t\t\t}\n\t\t\treturn rows.map((row) => row.map(cell).join(',')).join('\\r\\n')\n\t\t},\n\n\t\t/** Download the shown entries as a CSV file. */\n\t\texportEntries() {\n\t\t\tconst blob = new Blob([this.entriesCsv()], { type: 'text/csv;charset=utf-8' })\n\t\t\tconst url = URL.createObjectURL(blob)\n\t\t\tconst link = document.createElement('a')\n\t\t\tlink.href = url\n\t\t\tlink.download = `${this.content.exportName || 'history'}-${this.objectId || 'record'}.csv`\n\t\t\tdocument.body.appendChild(link)\n\t\t\tlink.click()\n\t\t\tlink.remove()\n\t\t\tURL.revokeObjectURL(url)\n\t\t},\n\n\t\t/**\n\t\t * Open the object sidebar on its audit trail tab.\n\t\t *\n\t\t * @spec openspec/changes/timeline-audit-trail-link/specs/timeline/spec.md#requirement-the-manage-timeline-can-point-at-the-audit-trail-in-the-sidebar\n\t\t */\n\t\topenAuditTrail() {\n\t\t\tthis.objectSidebarState.open = true\n\t\t\tthis.objectSidebarState.requestedTab = this.content.auditTrailTab || 'auditTrail'\n\t\t},\n\n\t\t/** Bring the composer into view and focus its text; a separate form card is asked to do so. */\n\t\tfocusComposer() {\n\t\t\tif (this.composerSeparate) {\n\t\t\t\temit(TIMELINE_COMPOSE, { objectId: this.objectId })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = this.$refs.composer\n\t\t\tif (!form) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tform.scrollIntoView?.({ behavior: 'smooth', block: 'center' })\n\t\t\tform.querySelector('textarea')?.focus()\n\t\t},\n\n\t\t/**\n\t\t * The label of one entry's kind, falling back to \"Note\".\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The label.\n\t\t */\n\t\tkindLabel(entry) {\n\t\t\tif (entry.kind === READ_KIND) {\n\t\t\t\treturn t('nextcloud-vue', 'Viewed')\n\t\t\t}\n\t\t\tif (!entry.kind) {\n\t\t\t\treturn t('nextcloud-vue', 'Note')\n\t\t\t}\n\t\t\tconst declared = this.kinds.find((kind) => kind.slug === entry.kind)\n\t\t\treturn declared?.title || entry.kind\n\t\t},\n\n\t\t/**\n\t\t * One moment in the reader's locale.\n\t\t *\n\t\t * @param {string} value An ISO 8601 stamp.\n\t\t * @return {string} The moment, or the raw value.\n\t\t */\n\t\tmoment(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parsed = new Date(value)\n\t\t\treturn isNaN(parsed.getTime()) ? value : parsed.toLocaleString()\n\t\t},\n\n\t\tasync togglePin(entry) {\n\t\t\tawait this.patch(entry, { pinned: !entry.pinned })\n\t\t},\n\n\t\tasync closeFollowUp(entry) {\n\t\t\tawait this.patch(entry, { followUp: 'done' })\n\t\t},\n\n\t\t/**\n\t\t * Write one change onto one entry and read the timeline back (pinning\n\t\t * changes the order, so patching in place would look like nothing).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {object} changes The fields to write.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync patch(entry, changes) {\n\t\t\ttry {\n\t\t\t\tawait axios.patch(`${this.timelineUrl}/${entry.id}`, changes)\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That change could not be saved.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The configured entry actions that apply to one entry (`kinds` limits\n\t\t * an action to entries of those kinds).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {Array<object>} The actions.\n\t\t */\n\t\tactionsFor(entry) {\n\t\t\treturn this.entryActions.filter((action) => !Array.isArray(action.kinds) || action.kinds.includes(entry.kind || ''))\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId` and `@row.<path>` tokens in an action's props.\n\t\t *\n\t\t * @param {object} props The props as declared.\n\t\t * @param {object} entry The entry.\n\t\t * @return {object} The resolved props.\n\t\t */\n\t\tresolveProps(props, entry) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(props || {})) {\n\t\t\t\tif (value === '@objectId') {\n\t\t\t\t\tout[key] = this.objectId\n\t\t\t\t} else if (typeof value === 'string' && value.startsWith('@row.')) {\n\t\t\t\t\tconst found = readPath(entry, value.slice('@row.'.length))\n\t\t\t\t\tout[key] = found === undefined || found === null ? '' : found\n\t\t\t\t} else {\n\t\t\t\t\tout[key] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Open an entry action's modal from the app's registry. On its\n\t\t * `doneEvent` (default `done`) the entry's open follow-up is closed when\n\t\t * the action says so; otherwise the timeline is read again.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} entry The entry.\n\t\t */\n\t\topenAction(action, entry) {\n\t\t\tconst registered = (this.cnRegistry || {})[action.modal]\n\t\t\tconst component = registered && (registered.component || registered)\n\t\t\tif (!component) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnTimelineWidget] entry action \"${action.id}\" names modal \"${action.modal}\", which the registry does not hold.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst close = () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t}\n\t\t\tconst done = async () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t\tif (action.closesFollowUp === true && entry.followUp === 'open') {\n\t\t\t\t\tawait this.closeFollowUp(entry)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.load()\n\t\t\t}\n\t\t\tthis.activeModal = {\n\t\t\t\tcomponent,\n\t\t\t\tprops: this.resolveProps(action.props, entry),\n\t\t\t\tlisteners: { [action.doneEvent || 'done']: done, close },\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-manage__header {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tmargin-block-end: 16px;\n}\n\n.cn-timeline-manage__heading {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-timeline-manage__header-actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__title {\n\tmargin: 0;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-timeline-manage__subtitle {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-timeline-manage__chips {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\theight: 36px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 18px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n}\n\n/* The chosen kind is a filled chip with no outline. */\n.cn-timeline-manage__chip--active {\n\tborder: 0;\n\tbackground: var(--color-main-text);\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__chip-count {\n\tpadding: 1px 7px;\n\tborder-radius: 10px;\n\tbackground: var(--color-border);\n\tcolor: var(--color-main-text);\n\tfont-size: 12px;\n}\n\n/* On the filled chip the count is a lighter ink bubble with light text. */\n.cn-timeline-manage__chip--active .cn-timeline-manage__chip-count {\n\tbackground: color-mix(in srgb, var(--color-main-background) 18%, var(--color-main-text));\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__footer {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tmargin: 12px 0 0;\n}\n\n.cn-timeline-manage__count {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__composer {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmargin-block-start: 24px;\n\tpadding-block-start: 16px;\n\tborder-block-start: 1px solid var(--color-border);\n}\n\n.cn-timeline-manage--composer-only .cn-timeline-manage__composer {\n\tmargin-block-start: 0;\n\tpadding-block-start: 0;\n\tborder-block-start: none;\n}\n\n/* The checkbox at the start, the button at the end, as one row. */\n.cn-timeline-manage__composer-foot {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__composer-title {\n\tmargin: 0;\n\tfont-size: 16px;\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__composer-hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__draft-label {\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__draft {\n\twidth: 100%;\n\tmin-height: 70px;\n}\n\n.cn-timeline-manage__controls {\n\tdisplay: flex;\n\tgap: 12px;\n\tflex-wrap: wrap;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__filter {\n\tmin-width: 200px;\n}\n\n.cn-timeline-manage__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-timeline-manage__entry {\n\tborder-block-end: 1px solid var(--color-border);\n\tpadding-block: 12px;\n}\n\n.cn-timeline-manage__entry--pinned {\n\tborder-inline-start: 3px solid var(--color-primary-element);\n\tpadding-inline-start: 8px;\n}\n\n.cn-timeline-manage__head {\n\tdisplay: flex;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__kind {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-manage__badge {\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tpadding: 0 6px;\n}\n\n.cn-timeline-manage__badge--open {\n\tborder-color: var(--color-warning);\n\tcolor: var(--color-warning-text);\n}\n\n.cn-timeline-manage__message {\n\tmargin-block: 4px 0;\n\twhite-space: pre-wrap;\n}\n\n.cn-timeline-manage__siblings {\n\tmargin-block: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-block-start: 4px;\n}\n</style>\n"],"names":["t","n","axios"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnTimelineManage.vue2.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineManage.vue"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n\n CnTimelineManage — the `manage` mode of CnTimelineWidget: one chronological\n read of OpenRegister's timeline on an object (notes, calls, messages), newest\n first with pinned entries on top, plus what a reader who may manage it can do\n there: filter by kind and visibility, pin, close a follow-up, write a note\n (optionally from a standard text block, optionally visible outside), export\n the shown entries as CSV, and run configured entry actions such as a reply\n dialog.\n\n The list read is filtered by OpenRegister whether or not a filter is asked\n for; the response says whether the reader may manage (`canManage`), and the\n controls are drawn from that rather than guessed. A failed read is not an\n empty history.\n-->\n<template>\n\t<div class=\"cn-timeline-manage\"\n\t\t:class=\"{ 'cn-timeline-manage--composer-only': composerOnly }\"\n\t\tdata-testid=\"cn-timeline-manage\">\n\t\t<template v-if=\"!composerOnly\">\n\t\t\t<div class=\"cn-timeline-manage__header\">\n\t\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t\t{{ titleText }}\n\t\t\t\t\t</h3>\n\t\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t\t{{ subtitleText }}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-timeline-manage__header-actions\">\n\t\t\t\t\t<NcButton v-if=\"canManage && (composerEnabled || composerSeparate)\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-add-note\"\n\t\t\t\t\t\t@click=\"focusComposer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Add note') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcButton data-testid=\"cn-timeline-export\" @click=\"exportEntries\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Export') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"cn-timeline-manage__chips\"\n\t\t\t\trole=\"group\"\n\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Kind')\"\n\t\t\t\tdata-testid=\"cn-timeline-kind-filter\">\n\t\t\t\t<button v-for=\"chip in kindChips\"\n\t\t\t\t\t:key=\"chip.key\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-timeline-manage__chip\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-manage__chip--active': chip.active }\"\n\t\t\t\t\t:aria-pressed=\"chip.active ? 'true' : 'false'\"\n\t\t\t\t\t:data-testid=\"'cn-timeline-chip-' + chip.key\"\n\t\t\t\t\t@click=\"chooseKind(chip.id)\">\n\t\t\t\t\t{{ chip.label }}\n\t\t\t\t\t<span class=\"cn-timeline-manage__chip-count\">{{ chip.count }}</span>\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<div class=\"cn-timeline-manage__controls\">\n\t\t\t\t<NcSelect v-if=\"canManage\"\n\t\t\t\t\tv-model=\"visibilityFilter\"\n\t\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t\t:options=\"visibilityOptions\"\n\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t:inputLabel=\"visibilityLabelShown ? t('nextcloud-vue', 'Visibility') : undefined\"\n\t\t\t\t\t:labelOutside=\"!visibilityLabelShown\"\n\t\t\t\t\t:ariaLabelCombobox=\"t('nextcloud-vue', 'Visibility')\"\n\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Internal and public')\"\n\t\t\t\t\tdata-testid=\"cn-timeline-visibility-filter\"\n\t\t\t\t\t@update:modelValue=\"load\" />\n\t\t\t</div>\n\n\t\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\n\t\t\t<NcNoteCard v-else-if=\"error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t\t{{ error }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<NcEmptyContent v-else-if=\"entries.length === 0\"\n\t\t\t\t:name=\"t('nextcloud-vue', 'Nothing recorded yet')\"\n\t\t\t\t:description=\"t('nextcloud-vue', 'Notes, calls and messages appear here in the order they happened.')\"\n\t\t\t\tdata-testid=\"cn-timeline-empty\" />\n\n\t\t\t<ul v-else class=\"cn-timeline-manage__list\" data-testid=\"cn-timeline-list\">\n\t\t\t\t<li v-for=\"entry in entries\"\n\t\t\t\t\t:key=\"entry.id\"\n\t\t\t\t\tclass=\"cn-timeline-manage__entry\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-manage__entry--pinned': entry.pinned }\"\n\t\t\t\t\t:data-kind=\"entry.kind || 'note'\"\n\t\t\t\t\tdata-testid=\"cn-timeline-entry\">\n\t\t\t\t\t<div class=\"cn-timeline-manage__head\">\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__kind\">{{ kindLabel(entry) }}</span>\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__author\">{{ entry.author }}</span>\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__moment\">{{ moment(entry.created) }}</span>\n\t\t\t\t\t\t<span v-if=\"entry.visibility === 'public'\"\n\t\t\t\t\t\t\tclass=\"cn-timeline-manage__badge cn-timeline-manage__badge--public\"\n\t\t\t\t\t\t\tdata-testid=\"cn-timeline-public\">\n\t\t\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\t\tclass=\"cn-timeline-manage__badge cn-timeline-manage__badge--open\"\n\t\t\t\t\t\t\tdata-testid=\"cn-timeline-followup-open\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Needs an answer') }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<p class=\"cn-timeline-manage__message\">\n\t\t\t\t\t\t{{ entry.message }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<p v-if=\"entry.siblings && entry.siblings.length\"\n\t\t\t\t\t\tclass=\"cn-timeline-manage__siblings\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-siblings\">\n\t\t\t\t\t\t{{ n('nextcloud-vue', 'Also written on %n other record', 'Also written on %n other records', entry.siblings.length) }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<div v-if=\"canManage && !entry.isRead\" class=\"cn-timeline-manage__actions\">\n\t\t\t\t\t\t<NcButton variant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-pin-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"togglePin(entry)\">\n\t\t\t\t\t\t\t{{ entry.pinned ? t('nextcloud-vue', 'Unpin') : t('nextcloud-vue', 'Pin') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton v-for=\"action in actionsFor(entry)\"\n\t\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-action-' + action.id + '-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"openAction(action, entry)\">\n\t\t\t\t\t\t\t{{ translate(action.label) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-followup-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"closeFollowUp(entry)\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Mark as answered') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\n\t\t\t<div v-if=\"(!loading && !error && allEntries.length > 0) || auditTrailLinkLabel || readsToggleLabel\"\n\t\t\t\tclass=\"cn-timeline-manage__footer\">\n\t\t\t\t<p v-if=\"!loading && !error && allEntries.length > 0\"\n\t\t\t\t\tclass=\"cn-timeline-manage__count\"\n\t\t\t\t\tdata-testid=\"cn-timeline-count\">\n\t\t\t\t\t{{ countLine }}\n\t\t\t\t</p>\n\t\t\t\t<NcCheckboxRadioSwitch v-if=\"readsToggleLabel && readsAllowed\"\n\t\t\t\t\tv-model=\"includeReads\"\n\t\t\t\t\tdata-testid=\"cn-timeline-include-reads\"\n\t\t\t\t\t@update:modelValue=\"load\">\n\t\t\t\t\t{{ readsToggleLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<NcButton v-if=\"auditTrailLinkLabel\"\n\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\tclass=\"cn-timeline-manage__audit-link\"\n\t\t\t\t\tdata-testid=\"cn-timeline-audit-link\"\n\t\t\t\t\t@click=\"openAuditTrail\">\n\t\t\t\t\t{{ auditTrailLinkLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<div v-if=\"composerOnly && canManage && composerEnabled\"\n\t\t\tclass=\"cn-timeline-manage__header\"\n\t\t\tdata-testid=\"cn-timeline-composer-heading\">\n\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t{{ composerTitleText }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t{{ composerSubtitleText }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-if=\"composerOnly && error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<form v-if=\"canManage && composerEnabled\"\n\t\t\tref=\"composer\"\n\t\t\tclass=\"cn-timeline-manage__composer\"\n\t\t\tdata-testid=\"cn-timeline-composer\"\n\t\t\t@submit.prevent=\"submit\">\n\t\t\t<template v-if=\"!composerOnly\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__composer-title\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add note') }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__composer-hint\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible') }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t\t<label v-if=\"textBlocks.length\" class=\"cn-timeline-manage__draft-label\" :for=\"blockId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Template') }}\n\t\t\t</label>\n\t\t\t<NcSelect v-if=\"textBlocks.length\"\n\t\t\t\tv-model=\"chosenBlock\"\n\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t:options=\"blockOptions\"\n\t\t\t\t:clearable=\"true\"\n\t\t\t\tlabel=\"label\"\n\t\t\t\t:inputId=\"blockId\"\n\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t:ariaLabelCombobox=\"t('nextcloud-vue', 'Template')\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write your own')\"\n\t\t\t\tdata-testid=\"cn-timeline-block\"\n\t\t\t\t@update:modelValue=\"pickBlock\" />\n\n\t\t\t<label class=\"cn-timeline-manage__draft-label\" :for=\"draftId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Note') }}\n\t\t\t</label>\n\t\t\t<textarea :id=\"draftId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-timeline-manage__draft\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write a note on this record')\"\n\t\t\t\tdata-testid=\"cn-timeline-draft\" />\n\n\t\t\t<div class=\"cn-timeline-manage__composer-foot\">\n\t\t\t\t<NcCheckboxRadioSwitch v-model=\"draftIsPublic\" data-testid=\"cn-timeline-draft-public\">\n\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t\t<NcButton variant=\"primary\"\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t:disabled=\"saving || !draft.trim()\"\n\t\t\t\t\tdata-testid=\"cn-timeline-save\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add it to the timeline') }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</form>\n\n\t\t<component :is=\"activeModal.component\"\n\t\t\tv-if=\"activeModal\"\n\t\t\tv-bind=\"activeModal.props\"\n\t\t\tv-on=\"activeModal.listeners\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport { prefixUrl } from '../../utils/headers.js'\n\nlet instanceCount = 0\n\n/** The kind of a read row (`readsToggle`), never a kind OpenRegister declares. */\nconst READ_KIND = 'cn-read'\n\n/** Event-bus channel: a note was added to an object's timeline (`{ objectId, source }`). */\nconst TIMELINE_CHANGED = 'cn:timeline:changed'\n\n/** Event-bus channel: the list's \"Add note\" asks the separate form card to take focus (`{ objectId }`). */\nconst TIMELINE_COMPOSE = 'cn:timeline:compose'\n\n/**\n * Read a dotted path off a value.\n *\n * @param {object} value The value.\n * @param {string} path The path.\n * @return {unknown} What is there, or undefined.\n */\nfunction readPath(value, path) {\n\treturn String(path).split('.').reduce((at, key) => (at === null || at === undefined ? undefined : at[key]), value)\n}\n\nexport default {\n\tname: 'CnTimelineManage',\n\n\tcomponents: { Download, NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect, Plus },\n\n\tinject: {\n\t\t/** The app's component registry; entry actions resolve their modal here. */\n\t\tcnRegistry: { default: () => ({}) },\n\t\t/** Consumer translation function; manifest labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's object sidebar channel; the audit trail link opens its tab. */\n\t\tobjectSidebarState: { default: null },\n\t},\n\n\tprops: {\n\t\t/** Register slug. */\n\t\tregister: { type: String, default: '' },\n\t\t/** Schema slug. */\n\t\tschema: { type: String, default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/**\n\t\t * The widget content: `{ title?, subtitle?, publicLabel?, exportName?,\n\t\t * composer?, textBlocks?, entryActions?, auditTrailLink? }`.\n\t\t * `composer`: `true` (default) draws the note form under the list,\n\t\t * `false` none, `\"separate\"` none but keeps the \"Add note\" button,\n\t\t * which brings a `\"only\"` instance (the form alone, a card of its own\n\t\t * in a stack) into view; a note saved there reloads the list.\n\t\t * `readsToggle` (`true` or a label) adds a footer switch, off by\n\t\t * default, that puts who read the record (its audit trail's reads)\n\t\t * among the entries; the count then says \"changes only\" while it is off.\n\t\t * `auditTrailLink` (`true` or a label) draws a footer link that opens\n\t\t * the object sidebar on its audit trail tab, `auditTrailTab` when the\n\t\t * page declares that tab under its own id.\n\t\t */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t},\n\n\tdata() {\n\t\tinstanceCount += 1\n\t\treturn {\n\t\t\tuid: instanceCount,\n\t\t\tallEntries: [],\n\t\t\tentries: [],\n\t\t\tkinds: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tcanManage: false,\n\t\t\tkindFilter: null,\n\t\t\tvisibilityFilter: null,\n\t\t\ttextBlocks: [],\n\t\t\tchosenBlock: null,\n\t\t\tdraft: '',\n\t\t\tdraftIsPublic: false,\n\t\t\tsaving: false,\n\t\t\tactiveModal: null,\n\t\t\t/** Whether the list also shows who read the record (`readsToggle`). */\n\t\t\tincludeReads: false,\n\t\t\t/** Whether OpenRegister gives this reader read entries (`readEventsVisible`); null until asked. */\n\t\t\treadsAllowed: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\ttitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'History')\n\t\t},\n\n\t\tsubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'What happened, who did it and when, newest first')\n\t\t},\n\n\t\t/** @return {string} The title of the note form's own card (`composer: \"only\"`): `content.title`, else Add note. */\n\t\tcomposerTitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'Add note')\n\t\t},\n\n\t\t/** @return {string} The line under that title: `content.subtitle`, else where the note goes. */\n\t\tcomposerSubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible')\n\t\t},\n\n\t\tpublicLabel() {\n\t\t\treturn this.content.publicLabel ? this.translate(this.content.publicLabel) : t('nextcloud-vue', 'Visible to the requester')\n\t\t},\n\n\t\t/**\n\t\t * The audit trail link's words, or '' when it is not drawn.\n\t\t *\n\t\t * @spec openspec/changes/timeline-audit-trail-link/specs/timeline/spec.md#requirement-the-manage-timeline-can-point-at-the-audit-trail-in-the-sidebar\n\t\t * @return {string}\n\t\t */\n\t\tauditTrailLinkLabel() {\n\t\t\tconst link = this.content.auditTrailLink\n\t\t\tif (!link || !this.objectSidebarState) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof link === 'string' ? this.translate(link) : t('nextcloud-vue', 'Full audit trail in the sidebar')\n\t\t},\n\n\t\t/**\n\t\t * Whether this instance draws the note form: inline (`composer` true or\n\t\t * unset) or as the whole widget (`\"only\"`).\n\t\t *\n\t\t * @spec openspec/changes/timeline-composer-card/specs/timeline/spec.md#requirement-the-note-form-can-be-its-own-card\n\t\t * @return {boolean}\n\t\t */\n\t\tcomposerEnabled() {\n\t\t\treturn this.content.composer !== false && this.content.composer !== 'separate'\n\t\t},\n\n\t\t/**\n\t\t * The words of the \"also who read it\" switch, or '' when the widget\n\t\t * does not offer it (`readsToggle`: true or a label).\n\t\t *\n\t\t * @spec openspec/changes/timeline-reads-toggle/specs/timeline/spec.md#requirement-the-history-can-show-who-read-the-record\n\t\t * @return {string}\n\t\t */\n\t\treadsToggleLabel() {\n\t\t\tconst toggle = this.content.readsToggle\n\t\t\tif (!toggle) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof toggle === 'string' ? this.translate(toggle) : t('nextcloud-vue', 'Also who read it')\n\t\t},\n\n\t\t/**\n\t\t * \"3 of 10 events\", and \", changes only\" while reads can be shown but are not.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tcountLine() {\n\t\t\tconst values = { shown: this.entries.length, total: this.allEntries.length }\n\t\t\treturn this.readsToggleLabel && this.readsAllowed && !this.includeReads\n\t\t\t\t? t('nextcloud-vue', '{shown} of {total} events, changes only', values)\n\t\t\t\t: t('nextcloud-vue', '{shown} of {total} events', values)\n\t\t},\n\n\t\t/**\n\t\t * Whether the visibility filter shows its \"Visibility\" label. With\n\t\t * `visibilityLabel: false` it keeps only its accessible name and the\n\t\t * select reads \"Internal and public\" on its own (board DqZaakHistorie).\n\t\t *\n\t\t * @spec openspec/changes/timeline-visibility-filter-unlabelled/specs/timeline/spec.md#requirement-the-visibility-filter-can-go-without-a-visible-label\n\t\t * @return {boolean}\n\t\t */\n\t\tvisibilityLabelShown() {\n\t\t\treturn this.content.visibilityLabel !== false\n\t\t},\n\n\t\t/** @return {boolean} The widget is the note form alone (`composer: \"only\"`), a card of its own beside the list. */\n\t\tcomposerOnly() {\n\t\t\treturn this.content.composer === 'only'\n\t\t},\n\n\t\t/** @return {boolean} The list draws no form; its \"Add note\" brings the separate form card into view (`composer: \"separate\"`). */\n\t\tcomposerSeparate() {\n\t\t\treturn this.content.composer === 'separate'\n\t\t},\n\n\t\tdraftId() {\n\t\t\treturn `cn-timeline-draft-${this.uid}`\n\t\t},\n\n\t\tblockId() {\n\t\t\treturn `cn-timeline-block-${this.uid}`\n\t\t},\n\n\t\t/**\n\t\t * The kind options, the plain note first. A note is an entry with NO\n\t\t * kind, so \"Note\" filters on its absence.\n\t\t *\n\t\t * @return {Array<object>} The options.\n\t\t */\n\t\tkindOptions() {\n\t\t\tconst options = [{ id: '', label: t('nextcloud-vue', 'Note') }].concat(this.kinds.map((kind) => ({ id: kind.slug, label: kind.title || kind.slug })))\n\t\t\treturn this.includeReads ? options.concat([{ id: READ_KIND, label: t('nextcloud-vue', 'Viewed') }]) : options\n\t\t},\n\n\t\t/**\n\t\t * All, then every kind the object has entries of, each with its count.\n\t\t *\n\t\t * @spec openspec/changes/timeline-all-chip-host-label/specs/timeline/spec.md#requirement-the-timelines-all-chip-reads-the-hosts-word\n\t\t * @return {Array<object>} The chips.\n\t\t */\n\t\tkindChips() {\n\t\t\tconst chosen = this.kindFilter ? (this.kindFilter.id || '') : null\n\t\t\tconst counts = new Map()\n\t\t\tfor (const entry of this.allEntries) {\n\t\t\t\tconst kind = entry.kind || ''\n\t\t\t\tcounts.set(kind, (counts.get(kind) || 0) + 1)\n\t\t\t}\n\t\t\t// The host's word first, as its own filter chips read (\"Alles\"), then the library's.\n\t\t\tconst hostAll = typeof this.cnTranslate === 'function' ? this.cnTranslate('All') : 'All'\n\t\t\tconst allLabel = typeof hostAll === 'string' && hostAll !== '' && hostAll !== 'All' ? hostAll : t('nextcloud-vue', 'All')\n\t\t\tconst chips = [{ key: 'all', id: null, label: allLabel, count: this.allEntries.length, active: chosen === null }]\n\t\t\tfor (const option of this.kindOptions) {\n\t\t\t\tconst count = counts.get(option.id) || 0\n\t\t\t\tif (count > 0) {\n\t\t\t\t\tchips.push({ key: option.id || 'note', id: option.id, label: option.label, count, active: chosen === option.id })\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn chips\n\t\t},\n\n\t\tblockOptions() {\n\t\t\treturn this.textBlocks.map((block) => ({ id: block.slug, label: block.title || block.slug }))\n\t\t},\n\n\t\tvisibilityOptions() {\n\t\t\treturn [\n\t\t\t\t{ id: 'internal', label: t('nextcloud-vue', 'Internal only') },\n\t\t\t\t{ id: 'public', label: this.publicLabel },\n\t\t\t]\n\t\t},\n\n\t\tbase() {\n\t\t\treturn this.apiBase.replace(/\\/$/, '')\n\t\t},\n\n\t\ttimelineUrl() {\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/timeline`)\n\t\t},\n\n\t\tentryActions() {\n\t\t\treturn Array.isArray(this.content.entryActions) ? this.content.entryActions.filter((action) => action && action.id) : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: 'load',\n\t},\n\n\tcreated() {\n\t\tthis.onTimelineChanged = (payload) => {\n\t\t\tif (!payload || payload.objectId !== this.objectId || payload.source === this.uid || this.composerOnly) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.load()\n\t\t}\n\t\tthis.onComposeRequested = (payload) => {\n\t\t\tif (this.composerOnly && payload && payload.objectId === this.objectId) {\n\t\t\t\tthis.focusComposer()\n\t\t\t}\n\t\t}\n\t\tsubscribe(TIMELINE_CHANGED, this.onTimelineChanged)\n\t\tsubscribe(TIMELINE_COMPOSE, this.onComposeRequested)\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(TIMELINE_CHANGED, this.onTimelineChanged)\n\t\tunsubscribe(TIMELINE_COMPOSE, this.onComposeRequested)\n\t},\n\n\tmounted() {\n\t\tthis.loadKinds()\n\t\tif (this.content.textBlocks !== false) {\n\t\t\tthis.loadTextBlocks()\n\t\t}\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tn,\n\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** Read the declared kinds, so the filter names them as administered. */\n\t\tasync loadKinds() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/kinds`))\n\t\t\t\tthis.kinds = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.kinds = []\n\t\t\t}\n\t\t},\n\n\t\t/** Read the seeded standard notes. */\n\t\tasync loadTextBlocks() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/text-blocks`))\n\t\t\t\tthis.textBlocks = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.textBlocks = []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Note which standard note was picked. The BLOCK is sent, not its body:\n\t\t * OpenRegister fills the object's own values into it on the way in.\n\t\t *\n\t\t * @param {object|null} block The picked option.\n\t\t */\n\t\tpickBlock(block) {\n\t\t\tthis.chosenBlock = block || null\n\t\t\tif (block) {\n\t\t\t\tconst declared = this.textBlocks.find((entry) => entry.slug === block.id)\n\t\t\t\tthis.draft = declared?.title || block.label\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write the drafted note onto this object.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tif (!this.draft.trim() || !this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst payload = { visibility: this.draftIsPublic ? 'public' : 'internal' }\n\t\t\t\tif (this.chosenBlock?.id) {\n\t\t\t\t\tpayload.textBlock = this.chosenBlock.id\n\t\t\t\t} else {\n\t\t\t\t\tpayload.message = this.draft\n\t\t\t\t}\n\t\t\t\tawait axios.post(this.timelineUrl, payload)\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.chosenBlock = null\n\t\t\t\tthis.draftIsPublic = false\n\t\t\t\temit(TIMELINE_CHANGED, { objectId: this.objectId, source: this.uid })\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That note could not be saved.')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the timeline with the visibility filter, if one is set.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst params = {}\n\t\t\t\tif (this.visibilityFilter?.id) {\n\t\t\t\t\tparams.visibility = this.visibilityFilter.id\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(this.timelineUrl, { params })\n\t\t\t\tthis.canManage = response.data?.canManage === true\n\t\t\t\tconst entries = response.data?.results || []\n\t\t\t\tif (this.readsToggleLabel && this.readsAllowed === null) {\n\t\t\t\t\tawait this.readEntries()\n\t\t\t\t}\n\t\t\t\tthis.allEntries = this.readsToggleLabel && this.readsAllowed && this.includeReads ? this.withReads(entries, await this.readEntries()) : entries\n\t\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t\t} catch {\n\t\t\t\tthis.allEntries = []\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'The timeline could not be read. Try again, or ask an administrator to check OpenRegister.')\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 * Who read the record, from its audit trail (`action=read`), as timeline\n\t\t * rows. OpenRegister gives read entries only to the groups named for\n\t\t * them and says so in `readEventsVisible`, which decides whether the\n\t\t * switch is offered at all; a read it refuses or that fails leaves the\n\t\t * reads out and offers no switch.\n\t\t *\n\t\t * @spec openspec/changes/timeline-reads-toggle/specs/timeline/spec.md#requirement-the-history-can-show-who-read-the-record\n\t\t * @return {Promise<Array<object>>} The read rows.\n\t\t */\n\t\tasync readEntries() {\n\t\t\ttry {\n\t\t\t\tconst url = prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails`)\n\t\t\t\tconst response = await axios.get(url, { params: { action: 'read', limit: 50 } })\n\t\t\t\tthis.readsAllowed = response.data?.readEventsVisible === true\n\t\t\t\tif (!this.readsAllowed) {\n\t\t\t\t\treturn []\n\t\t\t\t}\n\t\t\t\tconst list = response.data?.results || []\n\t\t\t\treturn list\n\t\t\t\t\t.filter((entry) => String(entry.action || '').toLowerCase() === 'read')\n\t\t\t\t\t.map((entry) => ({\n\t\t\t\t\t\tid: `read-${entry.id}`,\n\t\t\t\t\t\tkind: READ_KIND,\n\t\t\t\t\t\tisRead: true,\n\t\t\t\t\t\tauthor: entry.actorDisplayName || entry.userName || entry.user || '',\n\t\t\t\t\t\tcreated: entry.created || entry.creationDateTime || '',\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Opened the record'),\n\t\t\t\t\t}))\n\t\t\t} catch {\n\t\t\t\tthis.readsAllowed = false\n\t\t\t\treturn []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The timeline's entries with the reads among them, newest first; the\n\t\t * pinned entries stay on top.\n\t\t *\n\t\t * @param {Array<object>} entries The timeline's entries.\n\t\t * @param {Array<object>} reads The read rows.\n\t\t * @return {Array<object>} The merged list.\n\t\t */\n\t\twithReads(entries, reads) {\n\t\t\tconst time = (entry) => new Date(entry.created || 0).getTime() || 0\n\t\t\tconst pinned = entries.filter((entry) => entry.pinned)\n\t\t\tconst rest = [...entries.filter((entry) => !entry.pinned), ...reads].sort((a, b) => time(b) - time(a))\n\t\t\treturn [...pinned, ...rest]\n\t\t},\n\n\t\t/**\n\t\t * Show one kind, or every kind for `null`, without reading again.\n\t\t *\n\t\t * @param {string|null} id The kind slug, '' for a note, null for all.\n\t\t */\n\t\tchooseKind(id) {\n\t\t\tthis.kindFilter = id === null ? null : { id }\n\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t},\n\n\t\t/**\n\t\t * The kind filter is applied in the reading: the list endpoint does not\n\t\t * read a kind parameter, so sending one would be dropped in silence.\n\t\t *\n\t\t * @param {Array<object>} results The entries as read.\n\t\t * @return {Array<object>} The entries to show.\n\t\t */\n\t\tapplyKindFilter(results) {\n\t\t\tif (!this.kindFilter) {\n\t\t\t\treturn results\n\t\t\t}\n\t\t\tconst wanted = this.kindFilter.id || ''\n\t\t\treturn results.filter((entry) => (entry.kind || '') === wanted)\n\t\t},\n\n\t\t/**\n\t\t * The shown entries as CSV: when, kind, who, visibility and what.\n\t\t *\n\t\t * @return {string} The CSV text.\n\t\t */\n\t\tentriesCsv() {\n\t\t\tconst cell = (value) => `\"${String(value ?? '').replace(/\"/g, '\"\"')}\"`\n\t\t\tconst rows = [[t('nextcloud-vue', 'When'), t('nextcloud-vue', 'Kind'), t('nextcloud-vue', 'Who'), t('nextcloud-vue', 'Visibility'), t('nextcloud-vue', 'Message')]]\n\t\t\tfor (const entry of this.entries) {\n\t\t\t\trows.push([entry.created, this.kindLabel(entry), entry.author, entry.visibility, entry.message])\n\t\t\t}\n\t\t\treturn rows.map((row) => row.map(cell).join(',')).join('\\r\\n')\n\t\t},\n\n\t\t/** Download the shown entries as a CSV file. */\n\t\texportEntries() {\n\t\t\tconst blob = new Blob([this.entriesCsv()], { type: 'text/csv;charset=utf-8' })\n\t\t\tconst url = URL.createObjectURL(blob)\n\t\t\tconst link = document.createElement('a')\n\t\t\tlink.href = url\n\t\t\tlink.download = `${this.content.exportName || 'history'}-${this.objectId || 'record'}.csv`\n\t\t\tdocument.body.appendChild(link)\n\t\t\tlink.click()\n\t\t\tlink.remove()\n\t\t\tURL.revokeObjectURL(url)\n\t\t},\n\n\t\t/**\n\t\t * Open the object sidebar on its audit trail tab.\n\t\t *\n\t\t * @spec openspec/changes/timeline-audit-trail-link/specs/timeline/spec.md#requirement-the-manage-timeline-can-point-at-the-audit-trail-in-the-sidebar\n\t\t */\n\t\topenAuditTrail() {\n\t\t\tthis.objectSidebarState.open = true\n\t\t\tthis.objectSidebarState.requestedTab = this.content.auditTrailTab || 'auditTrail'\n\t\t},\n\n\t\t/** Bring the composer into view and focus its text; a separate form card is asked to do so. */\n\t\tfocusComposer() {\n\t\t\tif (this.composerSeparate) {\n\t\t\t\temit(TIMELINE_COMPOSE, { objectId: this.objectId })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = this.$refs.composer\n\t\t\tif (!form) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tform.scrollIntoView?.({ behavior: 'smooth', block: 'center' })\n\t\t\tform.querySelector('textarea')?.focus()\n\t\t},\n\n\t\t/**\n\t\t * The label of one entry's kind, falling back to \"Note\".\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The label.\n\t\t */\n\t\tkindLabel(entry) {\n\t\t\tif (entry.kind === READ_KIND) {\n\t\t\t\treturn t('nextcloud-vue', 'Viewed')\n\t\t\t}\n\t\t\tif (!entry.kind) {\n\t\t\t\treturn t('nextcloud-vue', 'Note')\n\t\t\t}\n\t\t\tconst declared = this.kinds.find((kind) => kind.slug === entry.kind)\n\t\t\treturn declared?.title || entry.kind\n\t\t},\n\n\t\t/**\n\t\t * One moment in the reader's locale.\n\t\t *\n\t\t * @param {string} value An ISO 8601 stamp.\n\t\t * @return {string} The moment, or the raw value.\n\t\t */\n\t\tmoment(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parsed = new Date(value)\n\t\t\treturn isNaN(parsed.getTime()) ? value : parsed.toLocaleString()\n\t\t},\n\n\t\tasync togglePin(entry) {\n\t\t\tawait this.patch(entry, { pinned: !entry.pinned })\n\t\t},\n\n\t\tasync closeFollowUp(entry) {\n\t\t\tawait this.patch(entry, { followUp: 'done' })\n\t\t},\n\n\t\t/**\n\t\t * Write one change onto one entry and read the timeline back (pinning\n\t\t * changes the order, so patching in place would look like nothing).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {object} changes The fields to write.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync patch(entry, changes) {\n\t\t\ttry {\n\t\t\t\tawait axios.patch(`${this.timelineUrl}/${entry.id}`, changes)\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That change could not be saved.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The configured entry actions that apply to one entry (`kinds` limits\n\t\t * an action to entries of those kinds).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {Array<object>} The actions.\n\t\t */\n\t\tactionsFor(entry) {\n\t\t\treturn this.entryActions.filter((action) => !Array.isArray(action.kinds) || action.kinds.includes(entry.kind || ''))\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId` and `@row.<path>` tokens in an action's props.\n\t\t *\n\t\t * @param {object} props The props as declared.\n\t\t * @param {object} entry The entry.\n\t\t * @return {object} The resolved props.\n\t\t */\n\t\tresolveProps(props, entry) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(props || {})) {\n\t\t\t\tif (value === '@objectId') {\n\t\t\t\t\tout[key] = this.objectId\n\t\t\t\t} else if (typeof value === 'string' && value.startsWith('@row.')) {\n\t\t\t\t\tconst found = readPath(entry, value.slice('@row.'.length))\n\t\t\t\t\tout[key] = found === undefined || found === null ? '' : found\n\t\t\t\t} else {\n\t\t\t\t\tout[key] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Open an entry action's modal from the app's registry. On its\n\t\t * `doneEvent` (default `done`) the entry's open follow-up is closed when\n\t\t * the action says so; otherwise the timeline is read again.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} entry The entry.\n\t\t */\n\t\topenAction(action, entry) {\n\t\t\tconst registered = (this.cnRegistry || {})[action.modal]\n\t\t\tconst component = registered && (registered.component || registered)\n\t\t\tif (!component) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnTimelineWidget] entry action \"${action.id}\" names modal \"${action.modal}\", which the registry does not hold.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst close = () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t}\n\t\t\tconst done = async () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t\tif (action.closesFollowUp === true && entry.followUp === 'open') {\n\t\t\t\t\tawait this.closeFollowUp(entry)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.load()\n\t\t\t}\n\t\t\tthis.activeModal = {\n\t\t\t\tcomponent,\n\t\t\t\tprops: this.resolveProps(action.props, entry),\n\t\t\t\tlisteners: { [action.doneEvent || 'done']: done, close },\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-manage__header {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tmargin-block-end: 16px;\n}\n\n.cn-timeline-manage__heading {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-timeline-manage__header-actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__title {\n\tmargin: 0;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-timeline-manage__subtitle {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-timeline-manage__chips {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\theight: 36px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 18px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n}\n\n/* The chosen kind is a filled chip with no outline. */\n.cn-timeline-manage__chip--active {\n\tborder: 0;\n\tbackground: var(--color-main-text);\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__chip-count {\n\tpadding: 1px 7px;\n\tborder-radius: 10px;\n\tbackground: var(--color-border);\n\tcolor: var(--color-main-text);\n\tfont-size: 12px;\n}\n\n/* On the filled chip the count is a lighter ink bubble with light text. */\n.cn-timeline-manage__chip--active .cn-timeline-manage__chip-count {\n\tbackground: color-mix(in srgb, var(--color-main-background) 18%, var(--color-main-text));\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__footer {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tmargin: 12px 0 0;\n}\n\n.cn-timeline-manage__count {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__composer {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmargin-block-start: 24px;\n\tpadding-block-start: 16px;\n\tborder-block-start: 1px solid var(--color-border);\n}\n\n.cn-timeline-manage--composer-only .cn-timeline-manage__composer {\n\tmargin-block-start: 0;\n\tpadding-block-start: 0;\n\tborder-block-start: none;\n}\n\n/* The checkbox at the start, the button at the end, as one row. */\n.cn-timeline-manage__composer-foot {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__composer-title {\n\tmargin: 0;\n\tfont-size: 16px;\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__composer-hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__draft-label {\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__draft {\n\twidth: 100%;\n\tmin-height: 70px;\n}\n\n.cn-timeline-manage__controls {\n\tdisplay: flex;\n\tgap: 12px;\n\tflex-wrap: wrap;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__filter {\n\tmin-width: 200px;\n}\n\n.cn-timeline-manage__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-timeline-manage__entry {\n\tborder-block-end: 1px solid var(--color-border);\n\tpadding-block: 12px;\n}\n\n.cn-timeline-manage__entry--pinned {\n\tborder-inline-start: 3px solid var(--color-primary-element);\n\tpadding-inline-start: 8px;\n}\n\n.cn-timeline-manage__head {\n\tdisplay: flex;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__kind {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-manage__badge {\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tpadding: 0 6px;\n}\n\n.cn-timeline-manage__badge--open {\n\tborder-color: var(--color-warning);\n\tcolor: var(--color-warning-text);\n}\n\n.cn-timeline-manage__message {\n\tmargin-block: 4px 0;\n\twhite-space: pre-wrap;\n}\n\n.cn-timeline-manage__siblings {\n\tmargin-block: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-block-start: 4px;\n}\n</style>\n"],"names":["t","n","axios"],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ const _hoisted_14 = { class: "cn-timeline-manage__author" };
|
|
|
21
21
|
const _hoisted_15 = { class: "cn-timeline-manage__moment" };
|
|
22
22
|
const _hoisted_16 = {
|
|
23
23
|
key: 0,
|
|
24
|
-
class: "cn-timeline-manage__badge",
|
|
24
|
+
class: "cn-timeline-manage__badge cn-timeline-manage__badge--public",
|
|
25
25
|
"data-testid": "cn-timeline-public"
|
|
26
26
|
};
|
|
27
27
|
const _hoisted_17 = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnTimelineManage.vue3.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineManage.vue?vue&type=template&id=31e6673c&lang.js"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n\n CnTimelineManage — the `manage` mode of CnTimelineWidget: one chronological\n read of OpenRegister's timeline on an object (notes, calls, messages), newest\n first with pinned entries on top, plus what a reader who may manage it can do\n there: filter by kind and visibility, pin, close a follow-up, write a note\n (optionally from a standard text block, optionally visible outside), export\n the shown entries as CSV, and run configured entry actions such as a reply\n dialog.\n\n The list read is filtered by OpenRegister whether or not a filter is asked\n for; the response says whether the reader may manage (`canManage`), and the\n controls are drawn from that rather than guessed. A failed read is not an\n empty history.\n-->\n<template>\n\t<div class=\"cn-timeline-manage\"\n\t\t:class=\"{ 'cn-timeline-manage--composer-only': composerOnly }\"\n\t\tdata-testid=\"cn-timeline-manage\">\n\t\t<template v-if=\"!composerOnly\">\n\t\t\t<div class=\"cn-timeline-manage__header\">\n\t\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t\t{{ titleText }}\n\t\t\t\t\t</h3>\n\t\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t\t{{ subtitleText }}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-timeline-manage__header-actions\">\n\t\t\t\t\t<NcButton v-if=\"canManage && (composerEnabled || composerSeparate)\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-add-note\"\n\t\t\t\t\t\t@click=\"focusComposer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Add note') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcButton data-testid=\"cn-timeline-export\" @click=\"exportEntries\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Export') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"cn-timeline-manage__chips\"\n\t\t\t\trole=\"group\"\n\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Kind')\"\n\t\t\t\tdata-testid=\"cn-timeline-kind-filter\">\n\t\t\t\t<button v-for=\"chip in kindChips\"\n\t\t\t\t\t:key=\"chip.key\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-timeline-manage__chip\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-manage__chip--active': chip.active }\"\n\t\t\t\t\t:aria-pressed=\"chip.active ? 'true' : 'false'\"\n\t\t\t\t\t:data-testid=\"'cn-timeline-chip-' + chip.key\"\n\t\t\t\t\t@click=\"chooseKind(chip.id)\">\n\t\t\t\t\t{{ chip.label }}\n\t\t\t\t\t<span class=\"cn-timeline-manage__chip-count\">{{ chip.count }}</span>\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<div class=\"cn-timeline-manage__controls\">\n\t\t\t\t<NcSelect v-if=\"canManage\"\n\t\t\t\t\tv-model=\"visibilityFilter\"\n\t\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t\t:options=\"visibilityOptions\"\n\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t:inputLabel=\"visibilityLabelShown ? t('nextcloud-vue', 'Visibility') : undefined\"\n\t\t\t\t\t:labelOutside=\"!visibilityLabelShown\"\n\t\t\t\t\t:ariaLabelCombobox=\"t('nextcloud-vue', 'Visibility')\"\n\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Internal and public')\"\n\t\t\t\t\tdata-testid=\"cn-timeline-visibility-filter\"\n\t\t\t\t\t@update:modelValue=\"load\" />\n\t\t\t</div>\n\n\t\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\n\t\t\t<NcNoteCard v-else-if=\"error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t\t{{ error }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<NcEmptyContent v-else-if=\"entries.length === 0\"\n\t\t\t\t:name=\"t('nextcloud-vue', 'Nothing recorded yet')\"\n\t\t\t\t:description=\"t('nextcloud-vue', 'Notes, calls and messages appear here in the order they happened.')\"\n\t\t\t\tdata-testid=\"cn-timeline-empty\" />\n\n\t\t\t<ul v-else class=\"cn-timeline-manage__list\" data-testid=\"cn-timeline-list\">\n\t\t\t\t<li v-for=\"entry in entries\"\n\t\t\t\t\t:key=\"entry.id\"\n\t\t\t\t\tclass=\"cn-timeline-manage__entry\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-manage__entry--pinned': entry.pinned }\"\n\t\t\t\t\t:data-kind=\"entry.kind || 'note'\"\n\t\t\t\t\tdata-testid=\"cn-timeline-entry\">\n\t\t\t\t\t<div class=\"cn-timeline-manage__head\">\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__kind\">{{ kindLabel(entry) }}</span>\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__author\">{{ entry.author }}</span>\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__moment\">{{ moment(entry.created) }}</span>\n\t\t\t\t\t\t<span v-if=\"entry.visibility === 'public'\"\n\t\t\t\t\t\t\tclass=\"cn-timeline-manage__badge\"\n\t\t\t\t\t\t\tdata-testid=\"cn-timeline-public\">\n\t\t\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\t\tclass=\"cn-timeline-manage__badge cn-timeline-manage__badge--open\"\n\t\t\t\t\t\t\tdata-testid=\"cn-timeline-followup-open\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Needs an answer') }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<p class=\"cn-timeline-manage__message\">\n\t\t\t\t\t\t{{ entry.message }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<p v-if=\"entry.siblings && entry.siblings.length\"\n\t\t\t\t\t\tclass=\"cn-timeline-manage__siblings\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-siblings\">\n\t\t\t\t\t\t{{ n('nextcloud-vue', 'Also written on %n other record', 'Also written on %n other records', entry.siblings.length) }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<div v-if=\"canManage && !entry.isRead\" class=\"cn-timeline-manage__actions\">\n\t\t\t\t\t\t<NcButton variant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-pin-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"togglePin(entry)\">\n\t\t\t\t\t\t\t{{ entry.pinned ? t('nextcloud-vue', 'Unpin') : t('nextcloud-vue', 'Pin') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton v-for=\"action in actionsFor(entry)\"\n\t\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-action-' + action.id + '-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"openAction(action, entry)\">\n\t\t\t\t\t\t\t{{ translate(action.label) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-followup-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"closeFollowUp(entry)\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Mark as answered') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\n\t\t\t<div v-if=\"(!loading && !error && allEntries.length > 0) || auditTrailLinkLabel || readsToggleLabel\"\n\t\t\t\tclass=\"cn-timeline-manage__footer\">\n\t\t\t\t<p v-if=\"!loading && !error && allEntries.length > 0\"\n\t\t\t\t\tclass=\"cn-timeline-manage__count\"\n\t\t\t\t\tdata-testid=\"cn-timeline-count\">\n\t\t\t\t\t{{ countLine }}\n\t\t\t\t</p>\n\t\t\t\t<NcCheckboxRadioSwitch v-if=\"readsToggleLabel && readsAllowed\"\n\t\t\t\t\tv-model=\"includeReads\"\n\t\t\t\t\tdata-testid=\"cn-timeline-include-reads\"\n\t\t\t\t\t@update:modelValue=\"load\">\n\t\t\t\t\t{{ readsToggleLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<NcButton v-if=\"auditTrailLinkLabel\"\n\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\tclass=\"cn-timeline-manage__audit-link\"\n\t\t\t\t\tdata-testid=\"cn-timeline-audit-link\"\n\t\t\t\t\t@click=\"openAuditTrail\">\n\t\t\t\t\t{{ auditTrailLinkLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<div v-if=\"composerOnly && canManage && composerEnabled\"\n\t\t\tclass=\"cn-timeline-manage__header\"\n\t\t\tdata-testid=\"cn-timeline-composer-heading\">\n\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t{{ composerTitleText }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t{{ composerSubtitleText }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-if=\"composerOnly && error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<form v-if=\"canManage && composerEnabled\"\n\t\t\tref=\"composer\"\n\t\t\tclass=\"cn-timeline-manage__composer\"\n\t\t\tdata-testid=\"cn-timeline-composer\"\n\t\t\t@submit.prevent=\"submit\">\n\t\t\t<template v-if=\"!composerOnly\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__composer-title\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add note') }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__composer-hint\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible') }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t\t<label v-if=\"textBlocks.length\" class=\"cn-timeline-manage__draft-label\" :for=\"blockId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Template') }}\n\t\t\t</label>\n\t\t\t<NcSelect v-if=\"textBlocks.length\"\n\t\t\t\tv-model=\"chosenBlock\"\n\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t:options=\"blockOptions\"\n\t\t\t\t:clearable=\"true\"\n\t\t\t\tlabel=\"label\"\n\t\t\t\t:inputId=\"blockId\"\n\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t:ariaLabelCombobox=\"t('nextcloud-vue', 'Template')\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write your own')\"\n\t\t\t\tdata-testid=\"cn-timeline-block\"\n\t\t\t\t@update:modelValue=\"pickBlock\" />\n\n\t\t\t<label class=\"cn-timeline-manage__draft-label\" :for=\"draftId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Note') }}\n\t\t\t</label>\n\t\t\t<textarea :id=\"draftId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-timeline-manage__draft\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write a note on this record')\"\n\t\t\t\tdata-testid=\"cn-timeline-draft\" />\n\n\t\t\t<div class=\"cn-timeline-manage__composer-foot\">\n\t\t\t\t<NcCheckboxRadioSwitch v-model=\"draftIsPublic\" data-testid=\"cn-timeline-draft-public\">\n\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t\t<NcButton variant=\"primary\"\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t:disabled=\"saving || !draft.trim()\"\n\t\t\t\t\tdata-testid=\"cn-timeline-save\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add it to the timeline') }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</form>\n\n\t\t<component :is=\"activeModal.component\"\n\t\t\tv-if=\"activeModal\"\n\t\t\tv-bind=\"activeModal.props\"\n\t\t\tv-on=\"activeModal.listeners\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport { prefixUrl } from '../../utils/headers.js'\n\nlet instanceCount = 0\n\n/** The kind of a read row (`readsToggle`), never a kind OpenRegister declares. */\nconst READ_KIND = 'cn-read'\n\n/** Event-bus channel: a note was added to an object's timeline (`{ objectId, source }`). */\nconst TIMELINE_CHANGED = 'cn:timeline:changed'\n\n/** Event-bus channel: the list's \"Add note\" asks the separate form card to take focus (`{ objectId }`). */\nconst TIMELINE_COMPOSE = 'cn:timeline:compose'\n\n/**\n * Read a dotted path off a value.\n *\n * @param {object} value The value.\n * @param {string} path The path.\n * @return {unknown} What is there, or undefined.\n */\nfunction readPath(value, path) {\n\treturn String(path).split('.').reduce((at, key) => (at === null || at === undefined ? undefined : at[key]), value)\n}\n\nexport default {\n\tname: 'CnTimelineManage',\n\n\tcomponents: { Download, NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect, Plus },\n\n\tinject: {\n\t\t/** The app's component registry; entry actions resolve their modal here. */\n\t\tcnRegistry: { default: () => ({}) },\n\t\t/** Consumer translation function; manifest labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's object sidebar channel; the audit trail link opens its tab. */\n\t\tobjectSidebarState: { default: null },\n\t},\n\n\tprops: {\n\t\t/** Register slug. */\n\t\tregister: { type: String, default: '' },\n\t\t/** Schema slug. */\n\t\tschema: { type: String, default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/**\n\t\t * The widget content: `{ title?, subtitle?, publicLabel?, exportName?,\n\t\t * composer?, textBlocks?, entryActions?, auditTrailLink? }`.\n\t\t * `composer`: `true` (default) draws the note form under the list,\n\t\t * `false` none, `\"separate\"` none but keeps the \"Add note\" button,\n\t\t * which brings a `\"only\"` instance (the form alone, a card of its own\n\t\t * in a stack) into view; a note saved there reloads the list.\n\t\t * `readsToggle` (`true` or a label) adds a footer switch, off by\n\t\t * default, that puts who read the record (its audit trail's reads)\n\t\t * among the entries; the count then says \"changes only\" while it is off.\n\t\t * `auditTrailLink` (`true` or a label) draws a footer link that opens\n\t\t * the object sidebar on its audit trail tab, `auditTrailTab` when the\n\t\t * page declares that tab under its own id.\n\t\t */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t},\n\n\tdata() {\n\t\tinstanceCount += 1\n\t\treturn {\n\t\t\tuid: instanceCount,\n\t\t\tallEntries: [],\n\t\t\tentries: [],\n\t\t\tkinds: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tcanManage: false,\n\t\t\tkindFilter: null,\n\t\t\tvisibilityFilter: null,\n\t\t\ttextBlocks: [],\n\t\t\tchosenBlock: null,\n\t\t\tdraft: '',\n\t\t\tdraftIsPublic: false,\n\t\t\tsaving: false,\n\t\t\tactiveModal: null,\n\t\t\t/** Whether the list also shows who read the record (`readsToggle`). */\n\t\t\tincludeReads: false,\n\t\t\t/** Whether OpenRegister gives this reader read entries (`readEventsVisible`); null until asked. */\n\t\t\treadsAllowed: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\ttitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'History')\n\t\t},\n\n\t\tsubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'What happened, who did it and when, newest first')\n\t\t},\n\n\t\t/** @return {string} The title of the note form's own card (`composer: \"only\"`): `content.title`, else Add note. */\n\t\tcomposerTitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'Add note')\n\t\t},\n\n\t\t/** @return {string} The line under that title: `content.subtitle`, else where the note goes. */\n\t\tcomposerSubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible')\n\t\t},\n\n\t\tpublicLabel() {\n\t\t\treturn this.content.publicLabel ? this.translate(this.content.publicLabel) : t('nextcloud-vue', 'Visible to the requester')\n\t\t},\n\n\t\t/**\n\t\t * The audit trail link's words, or '' when it is not drawn.\n\t\t *\n\t\t * @spec openspec/changes/timeline-audit-trail-link/specs/timeline/spec.md#requirement-the-manage-timeline-can-point-at-the-audit-trail-in-the-sidebar\n\t\t * @return {string}\n\t\t */\n\t\tauditTrailLinkLabel() {\n\t\t\tconst link = this.content.auditTrailLink\n\t\t\tif (!link || !this.objectSidebarState) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof link === 'string' ? this.translate(link) : t('nextcloud-vue', 'Full audit trail in the sidebar')\n\t\t},\n\n\t\t/**\n\t\t * Whether this instance draws the note form: inline (`composer` true or\n\t\t * unset) or as the whole widget (`\"only\"`).\n\t\t *\n\t\t * @spec openspec/changes/timeline-composer-card/specs/timeline/spec.md#requirement-the-note-form-can-be-its-own-card\n\t\t * @return {boolean}\n\t\t */\n\t\tcomposerEnabled() {\n\t\t\treturn this.content.composer !== false && this.content.composer !== 'separate'\n\t\t},\n\n\t\t/**\n\t\t * The words of the \"also who read it\" switch, or '' when the widget\n\t\t * does not offer it (`readsToggle`: true or a label).\n\t\t *\n\t\t * @spec openspec/changes/timeline-reads-toggle/specs/timeline/spec.md#requirement-the-history-can-show-who-read-the-record\n\t\t * @return {string}\n\t\t */\n\t\treadsToggleLabel() {\n\t\t\tconst toggle = this.content.readsToggle\n\t\t\tif (!toggle) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof toggle === 'string' ? this.translate(toggle) : t('nextcloud-vue', 'Also who read it')\n\t\t},\n\n\t\t/**\n\t\t * \"3 of 10 events\", and \", changes only\" while reads can be shown but are not.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tcountLine() {\n\t\t\tconst values = { shown: this.entries.length, total: this.allEntries.length }\n\t\t\treturn this.readsToggleLabel && this.readsAllowed && !this.includeReads\n\t\t\t\t? t('nextcloud-vue', '{shown} of {total} events, changes only', values)\n\t\t\t\t: t('nextcloud-vue', '{shown} of {total} events', values)\n\t\t},\n\n\t\t/**\n\t\t * Whether the visibility filter shows its \"Visibility\" label. With\n\t\t * `visibilityLabel: false` it keeps only its accessible name and the\n\t\t * select reads \"Internal and public\" on its own (board DqZaakHistorie).\n\t\t *\n\t\t * @spec openspec/changes/timeline-visibility-filter-unlabelled/specs/timeline/spec.md#requirement-the-visibility-filter-can-go-without-a-visible-label\n\t\t * @return {boolean}\n\t\t */\n\t\tvisibilityLabelShown() {\n\t\t\treturn this.content.visibilityLabel !== false\n\t\t},\n\n\t\t/** @return {boolean} The widget is the note form alone (`composer: \"only\"`), a card of its own beside the list. */\n\t\tcomposerOnly() {\n\t\t\treturn this.content.composer === 'only'\n\t\t},\n\n\t\t/** @return {boolean} The list draws no form; its \"Add note\" brings the separate form card into view (`composer: \"separate\"`). */\n\t\tcomposerSeparate() {\n\t\t\treturn this.content.composer === 'separate'\n\t\t},\n\n\t\tdraftId() {\n\t\t\treturn `cn-timeline-draft-${this.uid}`\n\t\t},\n\n\t\tblockId() {\n\t\t\treturn `cn-timeline-block-${this.uid}`\n\t\t},\n\n\t\t/**\n\t\t * The kind options, the plain note first. A note is an entry with NO\n\t\t * kind, so \"Note\" filters on its absence.\n\t\t *\n\t\t * @return {Array<object>} The options.\n\t\t */\n\t\tkindOptions() {\n\t\t\tconst options = [{ id: '', label: t('nextcloud-vue', 'Note') }].concat(this.kinds.map((kind) => ({ id: kind.slug, label: kind.title || kind.slug })))\n\t\t\treturn this.includeReads ? options.concat([{ id: READ_KIND, label: t('nextcloud-vue', 'Viewed') }]) : options\n\t\t},\n\n\t\t/**\n\t\t * All, then every kind the object has entries of, each with its count.\n\t\t *\n\t\t * @spec openspec/changes/timeline-all-chip-host-label/specs/timeline/spec.md#requirement-the-timelines-all-chip-reads-the-hosts-word\n\t\t * @return {Array<object>} The chips.\n\t\t */\n\t\tkindChips() {\n\t\t\tconst chosen = this.kindFilter ? (this.kindFilter.id || '') : null\n\t\t\tconst counts = new Map()\n\t\t\tfor (const entry of this.allEntries) {\n\t\t\t\tconst kind = entry.kind || ''\n\t\t\t\tcounts.set(kind, (counts.get(kind) || 0) + 1)\n\t\t\t}\n\t\t\t// The host's word first, as its own filter chips read (\"Alles\"), then the library's.\n\t\t\tconst hostAll = typeof this.cnTranslate === 'function' ? this.cnTranslate('All') : 'All'\n\t\t\tconst allLabel = typeof hostAll === 'string' && hostAll !== '' && hostAll !== 'All' ? hostAll : t('nextcloud-vue', 'All')\n\t\t\tconst chips = [{ key: 'all', id: null, label: allLabel, count: this.allEntries.length, active: chosen === null }]\n\t\t\tfor (const option of this.kindOptions) {\n\t\t\t\tconst count = counts.get(option.id) || 0\n\t\t\t\tif (count > 0) {\n\t\t\t\t\tchips.push({ key: option.id || 'note', id: option.id, label: option.label, count, active: chosen === option.id })\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn chips\n\t\t},\n\n\t\tblockOptions() {\n\t\t\treturn this.textBlocks.map((block) => ({ id: block.slug, label: block.title || block.slug }))\n\t\t},\n\n\t\tvisibilityOptions() {\n\t\t\treturn [\n\t\t\t\t{ id: 'internal', label: t('nextcloud-vue', 'Internal only') },\n\t\t\t\t{ id: 'public', label: this.publicLabel },\n\t\t\t]\n\t\t},\n\n\t\tbase() {\n\t\t\treturn this.apiBase.replace(/\\/$/, '')\n\t\t},\n\n\t\ttimelineUrl() {\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/timeline`)\n\t\t},\n\n\t\tentryActions() {\n\t\t\treturn Array.isArray(this.content.entryActions) ? this.content.entryActions.filter((action) => action && action.id) : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: 'load',\n\t},\n\n\tcreated() {\n\t\tthis.onTimelineChanged = (payload) => {\n\t\t\tif (!payload || payload.objectId !== this.objectId || payload.source === this.uid || this.composerOnly) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.load()\n\t\t}\n\t\tthis.onComposeRequested = (payload) => {\n\t\t\tif (this.composerOnly && payload && payload.objectId === this.objectId) {\n\t\t\t\tthis.focusComposer()\n\t\t\t}\n\t\t}\n\t\tsubscribe(TIMELINE_CHANGED, this.onTimelineChanged)\n\t\tsubscribe(TIMELINE_COMPOSE, this.onComposeRequested)\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(TIMELINE_CHANGED, this.onTimelineChanged)\n\t\tunsubscribe(TIMELINE_COMPOSE, this.onComposeRequested)\n\t},\n\n\tmounted() {\n\t\tthis.loadKinds()\n\t\tif (this.content.textBlocks !== false) {\n\t\t\tthis.loadTextBlocks()\n\t\t}\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tn,\n\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** Read the declared kinds, so the filter names them as administered. */\n\t\tasync loadKinds() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/kinds`))\n\t\t\t\tthis.kinds = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.kinds = []\n\t\t\t}\n\t\t},\n\n\t\t/** Read the seeded standard notes. */\n\t\tasync loadTextBlocks() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/text-blocks`))\n\t\t\t\tthis.textBlocks = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.textBlocks = []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Note which standard note was picked. The BLOCK is sent, not its body:\n\t\t * OpenRegister fills the object's own values into it on the way in.\n\t\t *\n\t\t * @param {object|null} block The picked option.\n\t\t */\n\t\tpickBlock(block) {\n\t\t\tthis.chosenBlock = block || null\n\t\t\tif (block) {\n\t\t\t\tconst declared = this.textBlocks.find((entry) => entry.slug === block.id)\n\t\t\t\tthis.draft = declared?.title || block.label\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write the drafted note onto this object.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tif (!this.draft.trim() || !this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst payload = { visibility: this.draftIsPublic ? 'public' : 'internal' }\n\t\t\t\tif (this.chosenBlock?.id) {\n\t\t\t\t\tpayload.textBlock = this.chosenBlock.id\n\t\t\t\t} else {\n\t\t\t\t\tpayload.message = this.draft\n\t\t\t\t}\n\t\t\t\tawait axios.post(this.timelineUrl, payload)\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.chosenBlock = null\n\t\t\t\tthis.draftIsPublic = false\n\t\t\t\temit(TIMELINE_CHANGED, { objectId: this.objectId, source: this.uid })\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That note could not be saved.')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the timeline with the visibility filter, if one is set.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst params = {}\n\t\t\t\tif (this.visibilityFilter?.id) {\n\t\t\t\t\tparams.visibility = this.visibilityFilter.id\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(this.timelineUrl, { params })\n\t\t\t\tthis.canManage = response.data?.canManage === true\n\t\t\t\tconst entries = response.data?.results || []\n\t\t\t\tif (this.readsToggleLabel && this.readsAllowed === null) {\n\t\t\t\t\tawait this.readEntries()\n\t\t\t\t}\n\t\t\t\tthis.allEntries = this.readsToggleLabel && this.readsAllowed && this.includeReads ? this.withReads(entries, await this.readEntries()) : entries\n\t\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t\t} catch {\n\t\t\t\tthis.allEntries = []\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'The timeline could not be read. Try again, or ask an administrator to check OpenRegister.')\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 * Who read the record, from its audit trail (`action=read`), as timeline\n\t\t * rows. OpenRegister gives read entries only to the groups named for\n\t\t * them and says so in `readEventsVisible`, which decides whether the\n\t\t * switch is offered at all; a read it refuses or that fails leaves the\n\t\t * reads out and offers no switch.\n\t\t *\n\t\t * @spec openspec/changes/timeline-reads-toggle/specs/timeline/spec.md#requirement-the-history-can-show-who-read-the-record\n\t\t * @return {Promise<Array<object>>} The read rows.\n\t\t */\n\t\tasync readEntries() {\n\t\t\ttry {\n\t\t\t\tconst url = prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails`)\n\t\t\t\tconst response = await axios.get(url, { params: { action: 'read', limit: 50 } })\n\t\t\t\tthis.readsAllowed = response.data?.readEventsVisible === true\n\t\t\t\tif (!this.readsAllowed) {\n\t\t\t\t\treturn []\n\t\t\t\t}\n\t\t\t\tconst list = response.data?.results || []\n\t\t\t\treturn list\n\t\t\t\t\t.filter((entry) => String(entry.action || '').toLowerCase() === 'read')\n\t\t\t\t\t.map((entry) => ({\n\t\t\t\t\t\tid: `read-${entry.id}`,\n\t\t\t\t\t\tkind: READ_KIND,\n\t\t\t\t\t\tisRead: true,\n\t\t\t\t\t\tauthor: entry.actorDisplayName || entry.userName || entry.user || '',\n\t\t\t\t\t\tcreated: entry.created || entry.creationDateTime || '',\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Opened the record'),\n\t\t\t\t\t}))\n\t\t\t} catch {\n\t\t\t\tthis.readsAllowed = false\n\t\t\t\treturn []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The timeline's entries with the reads among them, newest first; the\n\t\t * pinned entries stay on top.\n\t\t *\n\t\t * @param {Array<object>} entries The timeline's entries.\n\t\t * @param {Array<object>} reads The read rows.\n\t\t * @return {Array<object>} The merged list.\n\t\t */\n\t\twithReads(entries, reads) {\n\t\t\tconst time = (entry) => new Date(entry.created || 0).getTime() || 0\n\t\t\tconst pinned = entries.filter((entry) => entry.pinned)\n\t\t\tconst rest = [...entries.filter((entry) => !entry.pinned), ...reads].sort((a, b) => time(b) - time(a))\n\t\t\treturn [...pinned, ...rest]\n\t\t},\n\n\t\t/**\n\t\t * Show one kind, or every kind for `null`, without reading again.\n\t\t *\n\t\t * @param {string|null} id The kind slug, '' for a note, null for all.\n\t\t */\n\t\tchooseKind(id) {\n\t\t\tthis.kindFilter = id === null ? null : { id }\n\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t},\n\n\t\t/**\n\t\t * The kind filter is applied in the reading: the list endpoint does not\n\t\t * read a kind parameter, so sending one would be dropped in silence.\n\t\t *\n\t\t * @param {Array<object>} results The entries as read.\n\t\t * @return {Array<object>} The entries to show.\n\t\t */\n\t\tapplyKindFilter(results) {\n\t\t\tif (!this.kindFilter) {\n\t\t\t\treturn results\n\t\t\t}\n\t\t\tconst wanted = this.kindFilter.id || ''\n\t\t\treturn results.filter((entry) => (entry.kind || '') === wanted)\n\t\t},\n\n\t\t/**\n\t\t * The shown entries as CSV: when, kind, who, visibility and what.\n\t\t *\n\t\t * @return {string} The CSV text.\n\t\t */\n\t\tentriesCsv() {\n\t\t\tconst cell = (value) => `\"${String(value ?? '').replace(/\"/g, '\"\"')}\"`\n\t\t\tconst rows = [[t('nextcloud-vue', 'When'), t('nextcloud-vue', 'Kind'), t('nextcloud-vue', 'Who'), t('nextcloud-vue', 'Visibility'), t('nextcloud-vue', 'Message')]]\n\t\t\tfor (const entry of this.entries) {\n\t\t\t\trows.push([entry.created, this.kindLabel(entry), entry.author, entry.visibility, entry.message])\n\t\t\t}\n\t\t\treturn rows.map((row) => row.map(cell).join(',')).join('\\r\\n')\n\t\t},\n\n\t\t/** Download the shown entries as a CSV file. */\n\t\texportEntries() {\n\t\t\tconst blob = new Blob([this.entriesCsv()], { type: 'text/csv;charset=utf-8' })\n\t\t\tconst url = URL.createObjectURL(blob)\n\t\t\tconst link = document.createElement('a')\n\t\t\tlink.href = url\n\t\t\tlink.download = `${this.content.exportName || 'history'}-${this.objectId || 'record'}.csv`\n\t\t\tdocument.body.appendChild(link)\n\t\t\tlink.click()\n\t\t\tlink.remove()\n\t\t\tURL.revokeObjectURL(url)\n\t\t},\n\n\t\t/**\n\t\t * Open the object sidebar on its audit trail tab.\n\t\t *\n\t\t * @spec openspec/changes/timeline-audit-trail-link/specs/timeline/spec.md#requirement-the-manage-timeline-can-point-at-the-audit-trail-in-the-sidebar\n\t\t */\n\t\topenAuditTrail() {\n\t\t\tthis.objectSidebarState.open = true\n\t\t\tthis.objectSidebarState.requestedTab = this.content.auditTrailTab || 'auditTrail'\n\t\t},\n\n\t\t/** Bring the composer into view and focus its text; a separate form card is asked to do so. */\n\t\tfocusComposer() {\n\t\t\tif (this.composerSeparate) {\n\t\t\t\temit(TIMELINE_COMPOSE, { objectId: this.objectId })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = this.$refs.composer\n\t\t\tif (!form) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tform.scrollIntoView?.({ behavior: 'smooth', block: 'center' })\n\t\t\tform.querySelector('textarea')?.focus()\n\t\t},\n\n\t\t/**\n\t\t * The label of one entry's kind, falling back to \"Note\".\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The label.\n\t\t */\n\t\tkindLabel(entry) {\n\t\t\tif (entry.kind === READ_KIND) {\n\t\t\t\treturn t('nextcloud-vue', 'Viewed')\n\t\t\t}\n\t\t\tif (!entry.kind) {\n\t\t\t\treturn t('nextcloud-vue', 'Note')\n\t\t\t}\n\t\t\tconst declared = this.kinds.find((kind) => kind.slug === entry.kind)\n\t\t\treturn declared?.title || entry.kind\n\t\t},\n\n\t\t/**\n\t\t * One moment in the reader's locale.\n\t\t *\n\t\t * @param {string} value An ISO 8601 stamp.\n\t\t * @return {string} The moment, or the raw value.\n\t\t */\n\t\tmoment(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parsed = new Date(value)\n\t\t\treturn isNaN(parsed.getTime()) ? value : parsed.toLocaleString()\n\t\t},\n\n\t\tasync togglePin(entry) {\n\t\t\tawait this.patch(entry, { pinned: !entry.pinned })\n\t\t},\n\n\t\tasync closeFollowUp(entry) {\n\t\t\tawait this.patch(entry, { followUp: 'done' })\n\t\t},\n\n\t\t/**\n\t\t * Write one change onto one entry and read the timeline back (pinning\n\t\t * changes the order, so patching in place would look like nothing).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {object} changes The fields to write.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync patch(entry, changes) {\n\t\t\ttry {\n\t\t\t\tawait axios.patch(`${this.timelineUrl}/${entry.id}`, changes)\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That change could not be saved.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The configured entry actions that apply to one entry (`kinds` limits\n\t\t * an action to entries of those kinds).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {Array<object>} The actions.\n\t\t */\n\t\tactionsFor(entry) {\n\t\t\treturn this.entryActions.filter((action) => !Array.isArray(action.kinds) || action.kinds.includes(entry.kind || ''))\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId` and `@row.<path>` tokens in an action's props.\n\t\t *\n\t\t * @param {object} props The props as declared.\n\t\t * @param {object} entry The entry.\n\t\t * @return {object} The resolved props.\n\t\t */\n\t\tresolveProps(props, entry) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(props || {})) {\n\t\t\t\tif (value === '@objectId') {\n\t\t\t\t\tout[key] = this.objectId\n\t\t\t\t} else if (typeof value === 'string' && value.startsWith('@row.')) {\n\t\t\t\t\tconst found = readPath(entry, value.slice('@row.'.length))\n\t\t\t\t\tout[key] = found === undefined || found === null ? '' : found\n\t\t\t\t} else {\n\t\t\t\t\tout[key] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Open an entry action's modal from the app's registry. On its\n\t\t * `doneEvent` (default `done`) the entry's open follow-up is closed when\n\t\t * the action says so; otherwise the timeline is read again.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} entry The entry.\n\t\t */\n\t\topenAction(action, entry) {\n\t\t\tconst registered = (this.cnRegistry || {})[action.modal]\n\t\t\tconst component = registered && (registered.component || registered)\n\t\t\tif (!component) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnTimelineWidget] entry action \"${action.id}\" names modal \"${action.modal}\", which the registry does not hold.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst close = () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t}\n\t\t\tconst done = async () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t\tif (action.closesFollowUp === true && entry.followUp === 'open') {\n\t\t\t\t\tawait this.closeFollowUp(entry)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.load()\n\t\t\t}\n\t\t\tthis.activeModal = {\n\t\t\t\tcomponent,\n\t\t\t\tprops: this.resolveProps(action.props, entry),\n\t\t\t\tlisteners: { [action.doneEvent || 'done']: done, close },\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-manage__header {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tmargin-block-end: 16px;\n}\n\n.cn-timeline-manage__heading {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-timeline-manage__header-actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__title {\n\tmargin: 0;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-timeline-manage__subtitle {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-timeline-manage__chips {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\theight: 36px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 18px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n}\n\n/* The chosen kind is a filled chip with no outline. */\n.cn-timeline-manage__chip--active {\n\tborder: 0;\n\tbackground: var(--color-main-text);\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__chip-count {\n\tpadding: 1px 7px;\n\tborder-radius: 10px;\n\tbackground: var(--color-border);\n\tcolor: var(--color-main-text);\n\tfont-size: 12px;\n}\n\n/* On the filled chip the count is a lighter ink bubble with light text. */\n.cn-timeline-manage__chip--active .cn-timeline-manage__chip-count {\n\tbackground: color-mix(in srgb, var(--color-main-background) 18%, var(--color-main-text));\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__footer {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tmargin: 12px 0 0;\n}\n\n.cn-timeline-manage__count {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__composer {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmargin-block-start: 24px;\n\tpadding-block-start: 16px;\n\tborder-block-start: 1px solid var(--color-border);\n}\n\n.cn-timeline-manage--composer-only .cn-timeline-manage__composer {\n\tmargin-block-start: 0;\n\tpadding-block-start: 0;\n\tborder-block-start: none;\n}\n\n/* The checkbox at the start, the button at the end, as one row. */\n.cn-timeline-manage__composer-foot {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__composer-title {\n\tmargin: 0;\n\tfont-size: 16px;\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__composer-hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__draft-label {\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__draft {\n\twidth: 100%;\n\tmin-height: 70px;\n}\n\n.cn-timeline-manage__controls {\n\tdisplay: flex;\n\tgap: 12px;\n\tflex-wrap: wrap;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__filter {\n\tmin-width: 200px;\n}\n\n.cn-timeline-manage__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-timeline-manage__entry {\n\tborder-block-end: 1px solid var(--color-border);\n\tpadding-block: 12px;\n}\n\n.cn-timeline-manage__entry--pinned {\n\tborder-inline-start: 3px solid var(--color-primary-element);\n\tpadding-inline-start: 8px;\n}\n\n.cn-timeline-manage__head {\n\tdisplay: flex;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__kind {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-manage__badge {\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tpadding: 0 6px;\n}\n\n.cn-timeline-manage__badge--open {\n\tborder-color: var(--color-warning);\n\tcolor: var(--color-warning-text);\n}\n\n.cn-timeline-manage__message {\n\tmargin-block: 4px 0;\n\twhite-space: pre-wrap;\n}\n\n.cn-timeline-manage__siblings {\n\tmargin-block: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-block-start: 4px;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_Fragment","_createElementVNode","_toDisplayString","_createBlock","_createVNode","_createTextVNode","_openBlock","_renderList"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnTimelineManage.vue3.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineManage.vue?vue&type=template&id=0cd291df&lang.js"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n\n CnTimelineManage — the `manage` mode of CnTimelineWidget: one chronological\n read of OpenRegister's timeline on an object (notes, calls, messages), newest\n first with pinned entries on top, plus what a reader who may manage it can do\n there: filter by kind and visibility, pin, close a follow-up, write a note\n (optionally from a standard text block, optionally visible outside), export\n the shown entries as CSV, and run configured entry actions such as a reply\n dialog.\n\n The list read is filtered by OpenRegister whether or not a filter is asked\n for; the response says whether the reader may manage (`canManage`), and the\n controls are drawn from that rather than guessed. A failed read is not an\n empty history.\n-->\n<template>\n\t<div class=\"cn-timeline-manage\"\n\t\t:class=\"{ 'cn-timeline-manage--composer-only': composerOnly }\"\n\t\tdata-testid=\"cn-timeline-manage\">\n\t\t<template v-if=\"!composerOnly\">\n\t\t\t<div class=\"cn-timeline-manage__header\">\n\t\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t\t{{ titleText }}\n\t\t\t\t\t</h3>\n\t\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t\t{{ subtitleText }}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-timeline-manage__header-actions\">\n\t\t\t\t\t<NcButton v-if=\"canManage && (composerEnabled || composerSeparate)\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-add-note\"\n\t\t\t\t\t\t@click=\"focusComposer\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Add note') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcButton data-testid=\"cn-timeline-export\" @click=\"exportEntries\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Download :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Export') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"cn-timeline-manage__chips\"\n\t\t\t\trole=\"group\"\n\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Kind')\"\n\t\t\t\tdata-testid=\"cn-timeline-kind-filter\">\n\t\t\t\t<button v-for=\"chip in kindChips\"\n\t\t\t\t\t:key=\"chip.key\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-timeline-manage__chip\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-manage__chip--active': chip.active }\"\n\t\t\t\t\t:aria-pressed=\"chip.active ? 'true' : 'false'\"\n\t\t\t\t\t:data-testid=\"'cn-timeline-chip-' + chip.key\"\n\t\t\t\t\t@click=\"chooseKind(chip.id)\">\n\t\t\t\t\t{{ chip.label }}\n\t\t\t\t\t<span class=\"cn-timeline-manage__chip-count\">{{ chip.count }}</span>\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<div class=\"cn-timeline-manage__controls\">\n\t\t\t\t<NcSelect v-if=\"canManage\"\n\t\t\t\t\tv-model=\"visibilityFilter\"\n\t\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t\t:options=\"visibilityOptions\"\n\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t:inputLabel=\"visibilityLabelShown ? t('nextcloud-vue', 'Visibility') : undefined\"\n\t\t\t\t\t:labelOutside=\"!visibilityLabelShown\"\n\t\t\t\t\t:ariaLabelCombobox=\"t('nextcloud-vue', 'Visibility')\"\n\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Internal and public')\"\n\t\t\t\t\tdata-testid=\"cn-timeline-visibility-filter\"\n\t\t\t\t\t@update:modelValue=\"load\" />\n\t\t\t</div>\n\n\t\t\t<NcLoadingIcon v-if=\"loading\" :size=\"32\" />\n\n\t\t\t<NcNoteCard v-else-if=\"error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t\t{{ error }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<NcEmptyContent v-else-if=\"entries.length === 0\"\n\t\t\t\t:name=\"t('nextcloud-vue', 'Nothing recorded yet')\"\n\t\t\t\t:description=\"t('nextcloud-vue', 'Notes, calls and messages appear here in the order they happened.')\"\n\t\t\t\tdata-testid=\"cn-timeline-empty\" />\n\n\t\t\t<ul v-else class=\"cn-timeline-manage__list\" data-testid=\"cn-timeline-list\">\n\t\t\t\t<li v-for=\"entry in entries\"\n\t\t\t\t\t:key=\"entry.id\"\n\t\t\t\t\tclass=\"cn-timeline-manage__entry\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-manage__entry--pinned': entry.pinned }\"\n\t\t\t\t\t:data-kind=\"entry.kind || 'note'\"\n\t\t\t\t\tdata-testid=\"cn-timeline-entry\">\n\t\t\t\t\t<div class=\"cn-timeline-manage__head\">\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__kind\">{{ kindLabel(entry) }}</span>\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__author\">{{ entry.author }}</span>\n\t\t\t\t\t\t<span class=\"cn-timeline-manage__moment\">{{ moment(entry.created) }}</span>\n\t\t\t\t\t\t<span v-if=\"entry.visibility === 'public'\"\n\t\t\t\t\t\t\tclass=\"cn-timeline-manage__badge cn-timeline-manage__badge--public\"\n\t\t\t\t\t\t\tdata-testid=\"cn-timeline-public\">\n\t\t\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\t\tclass=\"cn-timeline-manage__badge cn-timeline-manage__badge--open\"\n\t\t\t\t\t\t\tdata-testid=\"cn-timeline-followup-open\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Needs an answer') }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<p class=\"cn-timeline-manage__message\">\n\t\t\t\t\t\t{{ entry.message }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<p v-if=\"entry.siblings && entry.siblings.length\"\n\t\t\t\t\t\tclass=\"cn-timeline-manage__siblings\"\n\t\t\t\t\t\tdata-testid=\"cn-timeline-siblings\">\n\t\t\t\t\t\t{{ n('nextcloud-vue', 'Also written on %n other record', 'Also written on %n other records', entry.siblings.length) }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<div v-if=\"canManage && !entry.isRead\" class=\"cn-timeline-manage__actions\">\n\t\t\t\t\t\t<NcButton variant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-pin-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"togglePin(entry)\">\n\t\t\t\t\t\t\t{{ entry.pinned ? t('nextcloud-vue', 'Unpin') : t('nextcloud-vue', 'Pin') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton v-for=\"action in actionsFor(entry)\"\n\t\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-action-' + action.id + '-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"openAction(action, entry)\">\n\t\t\t\t\t\t\t{{ translate(action.label) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton v-if=\"entry.followUp === 'open'\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"'cn-timeline-followup-' + entry.id\"\n\t\t\t\t\t\t\t@click=\"closeFollowUp(entry)\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Mark as answered') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\n\t\t\t<div v-if=\"(!loading && !error && allEntries.length > 0) || auditTrailLinkLabel || readsToggleLabel\"\n\t\t\t\tclass=\"cn-timeline-manage__footer\">\n\t\t\t\t<p v-if=\"!loading && !error && allEntries.length > 0\"\n\t\t\t\t\tclass=\"cn-timeline-manage__count\"\n\t\t\t\t\tdata-testid=\"cn-timeline-count\">\n\t\t\t\t\t{{ countLine }}\n\t\t\t\t</p>\n\t\t\t\t<NcCheckboxRadioSwitch v-if=\"readsToggleLabel && readsAllowed\"\n\t\t\t\t\tv-model=\"includeReads\"\n\t\t\t\t\tdata-testid=\"cn-timeline-include-reads\"\n\t\t\t\t\t@update:modelValue=\"load\">\n\t\t\t\t\t{{ readsToggleLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<NcButton v-if=\"auditTrailLinkLabel\"\n\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\tclass=\"cn-timeline-manage__audit-link\"\n\t\t\t\t\tdata-testid=\"cn-timeline-audit-link\"\n\t\t\t\t\t@click=\"openAuditTrail\">\n\t\t\t\t\t{{ auditTrailLinkLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<div v-if=\"composerOnly && canManage && composerEnabled\"\n\t\t\tclass=\"cn-timeline-manage__header\"\n\t\t\tdata-testid=\"cn-timeline-composer-heading\">\n\t\t\t<div class=\"cn-timeline-manage__heading\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__title\">\n\t\t\t\t\t{{ composerTitleText }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__subtitle\">\n\t\t\t\t\t{{ composerSubtitleText }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-if=\"composerOnly && error\" type=\"error\" data-testid=\"cn-timeline-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\n\t\t<form v-if=\"canManage && composerEnabled\"\n\t\t\tref=\"composer\"\n\t\t\tclass=\"cn-timeline-manage__composer\"\n\t\t\tdata-testid=\"cn-timeline-composer\"\n\t\t\t@submit.prevent=\"submit\">\n\t\t\t<template v-if=\"!composerOnly\">\n\t\t\t\t<h3 class=\"cn-timeline-manage__composer-title\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add note') }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-timeline-manage__composer-hint\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible') }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t\t<label v-if=\"textBlocks.length\" class=\"cn-timeline-manage__draft-label\" :for=\"blockId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Template') }}\n\t\t\t</label>\n\t\t\t<NcSelect v-if=\"textBlocks.length\"\n\t\t\t\tv-model=\"chosenBlock\"\n\t\t\t\tclass=\"cn-timeline-manage__filter\"\n\t\t\t\t:options=\"blockOptions\"\n\t\t\t\t:clearable=\"true\"\n\t\t\t\tlabel=\"label\"\n\t\t\t\t:inputId=\"blockId\"\n\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t:ariaLabelCombobox=\"t('nextcloud-vue', 'Template')\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write your own')\"\n\t\t\t\tdata-testid=\"cn-timeline-block\"\n\t\t\t\t@update:modelValue=\"pickBlock\" />\n\n\t\t\t<label class=\"cn-timeline-manage__draft-label\" :for=\"draftId\">\n\t\t\t\t{{ t('nextcloud-vue', 'Note') }}\n\t\t\t</label>\n\t\t\t<textarea :id=\"draftId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-timeline-manage__draft\"\n\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Write a note on this record')\"\n\t\t\t\tdata-testid=\"cn-timeline-draft\" />\n\n\t\t\t<div class=\"cn-timeline-manage__composer-foot\">\n\t\t\t\t<NcCheckboxRadioSwitch v-model=\"draftIsPublic\" data-testid=\"cn-timeline-draft-public\">\n\t\t\t\t\t{{ publicLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t\t<NcButton variant=\"primary\"\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t:disabled=\"saving || !draft.trim()\"\n\t\t\t\t\tdata-testid=\"cn-timeline-save\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Add it to the timeline') }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</form>\n\n\t\t<component :is=\"activeModal.component\"\n\t\t\tv-if=\"activeModal\"\n\t\t\tv-bind=\"activeModal.props\"\n\t\t\tv-on=\"activeModal.listeners\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue'\nimport Download from 'vue-material-design-icons/Download.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport { prefixUrl } from '../../utils/headers.js'\n\nlet instanceCount = 0\n\n/** The kind of a read row (`readsToggle`), never a kind OpenRegister declares. */\nconst READ_KIND = 'cn-read'\n\n/** Event-bus channel: a note was added to an object's timeline (`{ objectId, source }`). */\nconst TIMELINE_CHANGED = 'cn:timeline:changed'\n\n/** Event-bus channel: the list's \"Add note\" asks the separate form card to take focus (`{ objectId }`). */\nconst TIMELINE_COMPOSE = 'cn:timeline:compose'\n\n/**\n * Read a dotted path off a value.\n *\n * @param {object} value The value.\n * @param {string} path The path.\n * @return {unknown} What is there, or undefined.\n */\nfunction readPath(value, path) {\n\treturn String(path).split('.').reduce((at, key) => (at === null || at === undefined ? undefined : at[key]), value)\n}\n\nexport default {\n\tname: 'CnTimelineManage',\n\n\tcomponents: { Download, NcButton, NcCheckboxRadioSwitch, NcEmptyContent, NcLoadingIcon, NcNoteCard, NcSelect, Plus },\n\n\tinject: {\n\t\t/** The app's component registry; entry actions resolve their modal here. */\n\t\tcnRegistry: { default: () => ({}) },\n\t\t/** Consumer translation function; manifest labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's object sidebar channel; the audit trail link opens its tab. */\n\t\tobjectSidebarState: { default: null },\n\t},\n\n\tprops: {\n\t\t/** Register slug. */\n\t\tregister: { type: String, default: '' },\n\t\t/** Schema slug. */\n\t\tschema: { type: String, default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/**\n\t\t * The widget content: `{ title?, subtitle?, publicLabel?, exportName?,\n\t\t * composer?, textBlocks?, entryActions?, auditTrailLink? }`.\n\t\t * `composer`: `true` (default) draws the note form under the list,\n\t\t * `false` none, `\"separate\"` none but keeps the \"Add note\" button,\n\t\t * which brings a `\"only\"` instance (the form alone, a card of its own\n\t\t * in a stack) into view; a note saved there reloads the list.\n\t\t * `readsToggle` (`true` or a label) adds a footer switch, off by\n\t\t * default, that puts who read the record (its audit trail's reads)\n\t\t * among the entries; the count then says \"changes only\" while it is off.\n\t\t * `auditTrailLink` (`true` or a label) draws a footer link that opens\n\t\t * the object sidebar on its audit trail tab, `auditTrailTab` when the\n\t\t * page declares that tab under its own id.\n\t\t */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t},\n\n\tdata() {\n\t\tinstanceCount += 1\n\t\treturn {\n\t\t\tuid: instanceCount,\n\t\t\tallEntries: [],\n\t\t\tentries: [],\n\t\t\tkinds: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\tcanManage: false,\n\t\t\tkindFilter: null,\n\t\t\tvisibilityFilter: null,\n\t\t\ttextBlocks: [],\n\t\t\tchosenBlock: null,\n\t\t\tdraft: '',\n\t\t\tdraftIsPublic: false,\n\t\t\tsaving: false,\n\t\t\tactiveModal: null,\n\t\t\t/** Whether the list also shows who read the record (`readsToggle`). */\n\t\t\tincludeReads: false,\n\t\t\t/** Whether OpenRegister gives this reader read entries (`readEventsVisible`); null until asked. */\n\t\t\treadsAllowed: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\ttitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'History')\n\t\t},\n\n\t\tsubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'What happened, who did it and when, newest first')\n\t\t},\n\n\t\t/** @return {string} The title of the note form's own card (`composer: \"only\"`): `content.title`, else Add note. */\n\t\tcomposerTitleText() {\n\t\t\treturn this.content.title ? this.translate(this.content.title) : t('nextcloud-vue', 'Add note')\n\t\t},\n\n\t\t/** @return {string} The line under that title: `content.subtitle`, else where the note goes. */\n\t\tcomposerSubtitleText() {\n\t\t\treturn this.content.subtitle ? this.translate(this.content.subtitle) : t('nextcloud-vue', 'Goes on the timeline above, internal unless you make it visible')\n\t\t},\n\n\t\tpublicLabel() {\n\t\t\treturn this.content.publicLabel ? this.translate(this.content.publicLabel) : t('nextcloud-vue', 'Visible to the requester')\n\t\t},\n\n\t\t/**\n\t\t * The audit trail link's words, or '' when it is not drawn.\n\t\t *\n\t\t * @spec openspec/changes/timeline-audit-trail-link/specs/timeline/spec.md#requirement-the-manage-timeline-can-point-at-the-audit-trail-in-the-sidebar\n\t\t * @return {string}\n\t\t */\n\t\tauditTrailLinkLabel() {\n\t\t\tconst link = this.content.auditTrailLink\n\t\t\tif (!link || !this.objectSidebarState) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof link === 'string' ? this.translate(link) : t('nextcloud-vue', 'Full audit trail in the sidebar')\n\t\t},\n\n\t\t/**\n\t\t * Whether this instance draws the note form: inline (`composer` true or\n\t\t * unset) or as the whole widget (`\"only\"`).\n\t\t *\n\t\t * @spec openspec/changes/timeline-composer-card/specs/timeline/spec.md#requirement-the-note-form-can-be-its-own-card\n\t\t * @return {boolean}\n\t\t */\n\t\tcomposerEnabled() {\n\t\t\treturn this.content.composer !== false && this.content.composer !== 'separate'\n\t\t},\n\n\t\t/**\n\t\t * The words of the \"also who read it\" switch, or '' when the widget\n\t\t * does not offer it (`readsToggle`: true or a label).\n\t\t *\n\t\t * @spec openspec/changes/timeline-reads-toggle/specs/timeline/spec.md#requirement-the-history-can-show-who-read-the-record\n\t\t * @return {string}\n\t\t */\n\t\treadsToggleLabel() {\n\t\t\tconst toggle = this.content.readsToggle\n\t\t\tif (!toggle) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof toggle === 'string' ? this.translate(toggle) : t('nextcloud-vue', 'Also who read it')\n\t\t},\n\n\t\t/**\n\t\t * \"3 of 10 events\", and \", changes only\" while reads can be shown but are not.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tcountLine() {\n\t\t\tconst values = { shown: this.entries.length, total: this.allEntries.length }\n\t\t\treturn this.readsToggleLabel && this.readsAllowed && !this.includeReads\n\t\t\t\t? t('nextcloud-vue', '{shown} of {total} events, changes only', values)\n\t\t\t\t: t('nextcloud-vue', '{shown} of {total} events', values)\n\t\t},\n\n\t\t/**\n\t\t * Whether the visibility filter shows its \"Visibility\" label. With\n\t\t * `visibilityLabel: false` it keeps only its accessible name and the\n\t\t * select reads \"Internal and public\" on its own (board DqZaakHistorie).\n\t\t *\n\t\t * @spec openspec/changes/timeline-visibility-filter-unlabelled/specs/timeline/spec.md#requirement-the-visibility-filter-can-go-without-a-visible-label\n\t\t * @return {boolean}\n\t\t */\n\t\tvisibilityLabelShown() {\n\t\t\treturn this.content.visibilityLabel !== false\n\t\t},\n\n\t\t/** @return {boolean} The widget is the note form alone (`composer: \"only\"`), a card of its own beside the list. */\n\t\tcomposerOnly() {\n\t\t\treturn this.content.composer === 'only'\n\t\t},\n\n\t\t/** @return {boolean} The list draws no form; its \"Add note\" brings the separate form card into view (`composer: \"separate\"`). */\n\t\tcomposerSeparate() {\n\t\t\treturn this.content.composer === 'separate'\n\t\t},\n\n\t\tdraftId() {\n\t\t\treturn `cn-timeline-draft-${this.uid}`\n\t\t},\n\n\t\tblockId() {\n\t\t\treturn `cn-timeline-block-${this.uid}`\n\t\t},\n\n\t\t/**\n\t\t * The kind options, the plain note first. A note is an entry with NO\n\t\t * kind, so \"Note\" filters on its absence.\n\t\t *\n\t\t * @return {Array<object>} The options.\n\t\t */\n\t\tkindOptions() {\n\t\t\tconst options = [{ id: '', label: t('nextcloud-vue', 'Note') }].concat(this.kinds.map((kind) => ({ id: kind.slug, label: kind.title || kind.slug })))\n\t\t\treturn this.includeReads ? options.concat([{ id: READ_KIND, label: t('nextcloud-vue', 'Viewed') }]) : options\n\t\t},\n\n\t\t/**\n\t\t * All, then every kind the object has entries of, each with its count.\n\t\t *\n\t\t * @spec openspec/changes/timeline-all-chip-host-label/specs/timeline/spec.md#requirement-the-timelines-all-chip-reads-the-hosts-word\n\t\t * @return {Array<object>} The chips.\n\t\t */\n\t\tkindChips() {\n\t\t\tconst chosen = this.kindFilter ? (this.kindFilter.id || '') : null\n\t\t\tconst counts = new Map()\n\t\t\tfor (const entry of this.allEntries) {\n\t\t\t\tconst kind = entry.kind || ''\n\t\t\t\tcounts.set(kind, (counts.get(kind) || 0) + 1)\n\t\t\t}\n\t\t\t// The host's word first, as its own filter chips read (\"Alles\"), then the library's.\n\t\t\tconst hostAll = typeof this.cnTranslate === 'function' ? this.cnTranslate('All') : 'All'\n\t\t\tconst allLabel = typeof hostAll === 'string' && hostAll !== '' && hostAll !== 'All' ? hostAll : t('nextcloud-vue', 'All')\n\t\t\tconst chips = [{ key: 'all', id: null, label: allLabel, count: this.allEntries.length, active: chosen === null }]\n\t\t\tfor (const option of this.kindOptions) {\n\t\t\t\tconst count = counts.get(option.id) || 0\n\t\t\t\tif (count > 0) {\n\t\t\t\t\tchips.push({ key: option.id || 'note', id: option.id, label: option.label, count, active: chosen === option.id })\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn chips\n\t\t},\n\n\t\tblockOptions() {\n\t\t\treturn this.textBlocks.map((block) => ({ id: block.slug, label: block.title || block.slug }))\n\t\t},\n\n\t\tvisibilityOptions() {\n\t\t\treturn [\n\t\t\t\t{ id: 'internal', label: t('nextcloud-vue', 'Internal only') },\n\t\t\t\t{ id: 'public', label: this.publicLabel },\n\t\t\t]\n\t\t},\n\n\t\tbase() {\n\t\t\treturn this.apiBase.replace(/\\/$/, '')\n\t\t},\n\n\t\ttimelineUrl() {\n\t\t\tif (!this.objectId || !this.register || !this.schema) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/timeline`)\n\t\t},\n\n\t\tentryActions() {\n\t\t\treturn Array.isArray(this.content.entryActions) ? this.content.entryActions.filter((action) => action && action.id) : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: 'load',\n\t},\n\n\tcreated() {\n\t\tthis.onTimelineChanged = (payload) => {\n\t\t\tif (!payload || payload.objectId !== this.objectId || payload.source === this.uid || this.composerOnly) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.load()\n\t\t}\n\t\tthis.onComposeRequested = (payload) => {\n\t\t\tif (this.composerOnly && payload && payload.objectId === this.objectId) {\n\t\t\t\tthis.focusComposer()\n\t\t\t}\n\t\t}\n\t\tsubscribe(TIMELINE_CHANGED, this.onTimelineChanged)\n\t\tsubscribe(TIMELINE_COMPOSE, this.onComposeRequested)\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(TIMELINE_CHANGED, this.onTimelineChanged)\n\t\tunsubscribe(TIMELINE_COMPOSE, this.onComposeRequested)\n\t},\n\n\tmounted() {\n\t\tthis.loadKinds()\n\t\tif (this.content.textBlocks !== false) {\n\t\t\tthis.loadTextBlocks()\n\t\t}\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tn,\n\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** Read the declared kinds, so the filter names them as administered. */\n\t\tasync loadKinds() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/kinds`))\n\t\t\t\tthis.kinds = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.kinds = []\n\t\t\t}\n\t\t},\n\n\t\t/** Read the seeded standard notes. */\n\t\tasync loadTextBlocks() {\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(prefixUrl(`${this.base}/timeline/text-blocks`))\n\t\t\t\tthis.textBlocks = response.data?.results || []\n\t\t\t} catch {\n\t\t\t\tthis.textBlocks = []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Note which standard note was picked. The BLOCK is sent, not its body:\n\t\t * OpenRegister fills the object's own values into it on the way in.\n\t\t *\n\t\t * @param {object|null} block The picked option.\n\t\t */\n\t\tpickBlock(block) {\n\t\t\tthis.chosenBlock = block || null\n\t\t\tif (block) {\n\t\t\t\tconst declared = this.textBlocks.find((entry) => entry.slug === block.id)\n\t\t\t\tthis.draft = declared?.title || block.label\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Write the drafted note onto this object.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tif (!this.draft.trim() || !this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst payload = { visibility: this.draftIsPublic ? 'public' : 'internal' }\n\t\t\t\tif (this.chosenBlock?.id) {\n\t\t\t\t\tpayload.textBlock = this.chosenBlock.id\n\t\t\t\t} else {\n\t\t\t\t\tpayload.message = this.draft\n\t\t\t\t}\n\t\t\t\tawait axios.post(this.timelineUrl, payload)\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.chosenBlock = null\n\t\t\t\tthis.draftIsPublic = false\n\t\t\t\temit(TIMELINE_CHANGED, { objectId: this.objectId, source: this.uid })\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That note could not be saved.')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the timeline with the visibility filter, if one is set.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.timelineUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst params = {}\n\t\t\t\tif (this.visibilityFilter?.id) {\n\t\t\t\t\tparams.visibility = this.visibilityFilter.id\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(this.timelineUrl, { params })\n\t\t\t\tthis.canManage = response.data?.canManage === true\n\t\t\t\tconst entries = response.data?.results || []\n\t\t\t\tif (this.readsToggleLabel && this.readsAllowed === null) {\n\t\t\t\t\tawait this.readEntries()\n\t\t\t\t}\n\t\t\t\tthis.allEntries = this.readsToggleLabel && this.readsAllowed && this.includeReads ? this.withReads(entries, await this.readEntries()) : entries\n\t\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t\t} catch {\n\t\t\t\tthis.allEntries = []\n\t\t\t\tthis.entries = []\n\t\t\t\tthis.error = t('nextcloud-vue', 'The timeline could not be read. Try again, or ask an administrator to check OpenRegister.')\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 * Who read the record, from its audit trail (`action=read`), as timeline\n\t\t * rows. OpenRegister gives read entries only to the groups named for\n\t\t * them and says so in `readEventsVisible`, which decides whether the\n\t\t * switch is offered at all; a read it refuses or that fails leaves the\n\t\t * reads out and offers no switch.\n\t\t *\n\t\t * @spec openspec/changes/timeline-reads-toggle/specs/timeline/spec.md#requirement-the-history-can-show-who-read-the-record\n\t\t * @return {Promise<Array<object>>} The read rows.\n\t\t */\n\t\tasync readEntries() {\n\t\t\ttry {\n\t\t\t\tconst url = prefixUrl(`${this.base}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails`)\n\t\t\t\tconst response = await axios.get(url, { params: { action: 'read', limit: 50 } })\n\t\t\t\tthis.readsAllowed = response.data?.readEventsVisible === true\n\t\t\t\tif (!this.readsAllowed) {\n\t\t\t\t\treturn []\n\t\t\t\t}\n\t\t\t\tconst list = response.data?.results || []\n\t\t\t\treturn list\n\t\t\t\t\t.filter((entry) => String(entry.action || '').toLowerCase() === 'read')\n\t\t\t\t\t.map((entry) => ({\n\t\t\t\t\t\tid: `read-${entry.id}`,\n\t\t\t\t\t\tkind: READ_KIND,\n\t\t\t\t\t\tisRead: true,\n\t\t\t\t\t\tauthor: entry.actorDisplayName || entry.userName || entry.user || '',\n\t\t\t\t\t\tcreated: entry.created || entry.creationDateTime || '',\n\t\t\t\t\t\tmessage: t('nextcloud-vue', 'Opened the record'),\n\t\t\t\t\t}))\n\t\t\t} catch {\n\t\t\t\tthis.readsAllowed = false\n\t\t\t\treturn []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The timeline's entries with the reads among them, newest first; the\n\t\t * pinned entries stay on top.\n\t\t *\n\t\t * @param {Array<object>} entries The timeline's entries.\n\t\t * @param {Array<object>} reads The read rows.\n\t\t * @return {Array<object>} The merged list.\n\t\t */\n\t\twithReads(entries, reads) {\n\t\t\tconst time = (entry) => new Date(entry.created || 0).getTime() || 0\n\t\t\tconst pinned = entries.filter((entry) => entry.pinned)\n\t\t\tconst rest = [...entries.filter((entry) => !entry.pinned), ...reads].sort((a, b) => time(b) - time(a))\n\t\t\treturn [...pinned, ...rest]\n\t\t},\n\n\t\t/**\n\t\t * Show one kind, or every kind for `null`, without reading again.\n\t\t *\n\t\t * @param {string|null} id The kind slug, '' for a note, null for all.\n\t\t */\n\t\tchooseKind(id) {\n\t\t\tthis.kindFilter = id === null ? null : { id }\n\t\t\tthis.entries = this.applyKindFilter(this.allEntries)\n\t\t},\n\n\t\t/**\n\t\t * The kind filter is applied in the reading: the list endpoint does not\n\t\t * read a kind parameter, so sending one would be dropped in silence.\n\t\t *\n\t\t * @param {Array<object>} results The entries as read.\n\t\t * @return {Array<object>} The entries to show.\n\t\t */\n\t\tapplyKindFilter(results) {\n\t\t\tif (!this.kindFilter) {\n\t\t\t\treturn results\n\t\t\t}\n\t\t\tconst wanted = this.kindFilter.id || ''\n\t\t\treturn results.filter((entry) => (entry.kind || '') === wanted)\n\t\t},\n\n\t\t/**\n\t\t * The shown entries as CSV: when, kind, who, visibility and what.\n\t\t *\n\t\t * @return {string} The CSV text.\n\t\t */\n\t\tentriesCsv() {\n\t\t\tconst cell = (value) => `\"${String(value ?? '').replace(/\"/g, '\"\"')}\"`\n\t\t\tconst rows = [[t('nextcloud-vue', 'When'), t('nextcloud-vue', 'Kind'), t('nextcloud-vue', 'Who'), t('nextcloud-vue', 'Visibility'), t('nextcloud-vue', 'Message')]]\n\t\t\tfor (const entry of this.entries) {\n\t\t\t\trows.push([entry.created, this.kindLabel(entry), entry.author, entry.visibility, entry.message])\n\t\t\t}\n\t\t\treturn rows.map((row) => row.map(cell).join(',')).join('\\r\\n')\n\t\t},\n\n\t\t/** Download the shown entries as a CSV file. */\n\t\texportEntries() {\n\t\t\tconst blob = new Blob([this.entriesCsv()], { type: 'text/csv;charset=utf-8' })\n\t\t\tconst url = URL.createObjectURL(blob)\n\t\t\tconst link = document.createElement('a')\n\t\t\tlink.href = url\n\t\t\tlink.download = `${this.content.exportName || 'history'}-${this.objectId || 'record'}.csv`\n\t\t\tdocument.body.appendChild(link)\n\t\t\tlink.click()\n\t\t\tlink.remove()\n\t\t\tURL.revokeObjectURL(url)\n\t\t},\n\n\t\t/**\n\t\t * Open the object sidebar on its audit trail tab.\n\t\t *\n\t\t * @spec openspec/changes/timeline-audit-trail-link/specs/timeline/spec.md#requirement-the-manage-timeline-can-point-at-the-audit-trail-in-the-sidebar\n\t\t */\n\t\topenAuditTrail() {\n\t\t\tthis.objectSidebarState.open = true\n\t\t\tthis.objectSidebarState.requestedTab = this.content.auditTrailTab || 'auditTrail'\n\t\t},\n\n\t\t/** Bring the composer into view and focus its text; a separate form card is asked to do so. */\n\t\tfocusComposer() {\n\t\t\tif (this.composerSeparate) {\n\t\t\t\temit(TIMELINE_COMPOSE, { objectId: this.objectId })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = this.$refs.composer\n\t\t\tif (!form) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tform.scrollIntoView?.({ behavior: 'smooth', block: 'center' })\n\t\t\tform.querySelector('textarea')?.focus()\n\t\t},\n\n\t\t/**\n\t\t * The label of one entry's kind, falling back to \"Note\".\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {string} The label.\n\t\t */\n\t\tkindLabel(entry) {\n\t\t\tif (entry.kind === READ_KIND) {\n\t\t\t\treturn t('nextcloud-vue', 'Viewed')\n\t\t\t}\n\t\t\tif (!entry.kind) {\n\t\t\t\treturn t('nextcloud-vue', 'Note')\n\t\t\t}\n\t\t\tconst declared = this.kinds.find((kind) => kind.slug === entry.kind)\n\t\t\treturn declared?.title || entry.kind\n\t\t},\n\n\t\t/**\n\t\t * One moment in the reader's locale.\n\t\t *\n\t\t * @param {string} value An ISO 8601 stamp.\n\t\t * @return {string} The moment, or the raw value.\n\t\t */\n\t\tmoment(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst parsed = new Date(value)\n\t\t\treturn isNaN(parsed.getTime()) ? value : parsed.toLocaleString()\n\t\t},\n\n\t\tasync togglePin(entry) {\n\t\t\tawait this.patch(entry, { pinned: !entry.pinned })\n\t\t},\n\n\t\tasync closeFollowUp(entry) {\n\t\t\tawait this.patch(entry, { followUp: 'done' })\n\t\t},\n\n\t\t/**\n\t\t * Write one change onto one entry and read the timeline back (pinning\n\t\t * changes the order, so patching in place would look like nothing).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {object} changes The fields to write.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync patch(entry, changes) {\n\t\t\ttry {\n\t\t\t\tawait axios.patch(`${this.timelineUrl}/${entry.id}`, changes)\n\t\t\t\tawait this.load()\n\t\t\t} catch {\n\t\t\t\tthis.error = t('nextcloud-vue', 'That change could not be saved.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The configured entry actions that apply to one entry (`kinds` limits\n\t\t * an action to entries of those kinds).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {Array<object>} The actions.\n\t\t */\n\t\tactionsFor(entry) {\n\t\t\treturn this.entryActions.filter((action) => !Array.isArray(action.kinds) || action.kinds.includes(entry.kind || ''))\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId` and `@row.<path>` tokens in an action's props.\n\t\t *\n\t\t * @param {object} props The props as declared.\n\t\t * @param {object} entry The entry.\n\t\t * @return {object} The resolved props.\n\t\t */\n\t\tresolveProps(props, entry) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(props || {})) {\n\t\t\t\tif (value === '@objectId') {\n\t\t\t\t\tout[key] = this.objectId\n\t\t\t\t} else if (typeof value === 'string' && value.startsWith('@row.')) {\n\t\t\t\t\tconst found = readPath(entry, value.slice('@row.'.length))\n\t\t\t\t\tout[key] = found === undefined || found === null ? '' : found\n\t\t\t\t} else {\n\t\t\t\t\tout[key] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Open an entry action's modal from the app's registry. On its\n\t\t * `doneEvent` (default `done`) the entry's open follow-up is closed when\n\t\t * the action says so; otherwise the timeline is read again.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} entry The entry.\n\t\t */\n\t\topenAction(action, entry) {\n\t\t\tconst registered = (this.cnRegistry || {})[action.modal]\n\t\t\tconst component = registered && (registered.component || registered)\n\t\t\tif (!component) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnTimelineWidget] entry action \"${action.id}\" names modal \"${action.modal}\", which the registry does not hold.`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst close = () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t}\n\t\t\tconst done = async () => {\n\t\t\t\tthis.activeModal = null\n\t\t\t\tif (action.closesFollowUp === true && entry.followUp === 'open') {\n\t\t\t\t\tawait this.closeFollowUp(entry)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tawait this.load()\n\t\t\t}\n\t\t\tthis.activeModal = {\n\t\t\t\tcomponent,\n\t\t\t\tprops: this.resolveProps(action.props, entry),\n\t\t\t\tlisteners: { [action.doneEvent || 'done']: done, close },\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-manage__header {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tmargin-block-end: 16px;\n}\n\n.cn-timeline-manage__heading {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-timeline-manage__header-actions {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__title {\n\tmargin: 0;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-timeline-manage__subtitle {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-timeline-manage__chips {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\theight: 36px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 18px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n}\n\n/* The chosen kind is a filled chip with no outline. */\n.cn-timeline-manage__chip--active {\n\tborder: 0;\n\tbackground: var(--color-main-text);\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__chip-count {\n\tpadding: 1px 7px;\n\tborder-radius: 10px;\n\tbackground: var(--color-border);\n\tcolor: var(--color-main-text);\n\tfont-size: 12px;\n}\n\n/* On the filled chip the count is a lighter ink bubble with light text. */\n.cn-timeline-manage__chip--active .cn-timeline-manage__chip-count {\n\tbackground: color-mix(in srgb, var(--color-main-background) 18%, var(--color-main-text));\n\tcolor: var(--color-main-background);\n}\n\n.cn-timeline-manage__footer {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tmargin: 12px 0 0;\n}\n\n.cn-timeline-manage__count {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__composer {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmargin-block-start: 24px;\n\tpadding-block-start: 16px;\n\tborder-block-start: 1px solid var(--color-border);\n}\n\n.cn-timeline-manage--composer-only .cn-timeline-manage__composer {\n\tmargin-block-start: 0;\n\tpadding-block-start: 0;\n\tborder-block-start: none;\n}\n\n/* The checkbox at the start, the button at the end, as one row. */\n.cn-timeline-manage__composer-foot {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n}\n\n.cn-timeline-manage__composer-title {\n\tmargin: 0;\n\tfont-size: 16px;\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__composer-hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-manage__draft-label {\n\tfont-weight: bold;\n}\n\n.cn-timeline-manage__draft {\n\twidth: 100%;\n\tmin-height: 70px;\n}\n\n.cn-timeline-manage__controls {\n\tdisplay: flex;\n\tgap: 12px;\n\tflex-wrap: wrap;\n\tmargin-block-end: 12px;\n}\n\n.cn-timeline-manage__filter {\n\tmin-width: 200px;\n}\n\n.cn-timeline-manage__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-timeline-manage__entry {\n\tborder-block-end: 1px solid var(--color-border);\n\tpadding-block: 12px;\n}\n\n.cn-timeline-manage__entry--pinned {\n\tborder-inline-start: 3px solid var(--color-primary-element);\n\tpadding-inline-start: 8px;\n}\n\n.cn-timeline-manage__head {\n\tdisplay: flex;\n\tgap: 8px;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__kind {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-manage__badge {\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tpadding: 0 6px;\n}\n\n.cn-timeline-manage__badge--open {\n\tborder-color: var(--color-warning);\n\tcolor: var(--color-warning-text);\n}\n\n.cn-timeline-manage__message {\n\tmargin-block: 4px 0;\n\twhite-space: pre-wrap;\n}\n\n.cn-timeline-manage__siblings {\n\tmargin-block: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-timeline-manage__actions {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-block-start: 4px;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_Fragment","_createElementVNode","_toDisplayString","_createBlock","_createVNode","_createTextVNode","_openBlock","_renderList"],"mappings":"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"}
|