@conduction/nextcloud-vue 2.150.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.
Files changed (67) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +7 -2
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +40 -41
  5. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
  6. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
  7. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +6 -3
  8. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
  9. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +13 -1
  10. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
  11. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
  12. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +5 -1
  13. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
  14. package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
  15. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  16. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +46 -0
  17. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  18. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +64 -64
  19. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  20. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  21. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +15 -1
  22. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  23. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  24. package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue.js +1 -1
  25. package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue2.js.map +1 -1
  26. package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js +16 -5
  27. package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js.map +1 -1
  28. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  29. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +25 -2
  30. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  31. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +82 -68
  32. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  33. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
  34. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
  35. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
  36. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
  37. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
  38. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +1 -1
  39. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
  40. package/dist/esm/integrations/builtin/calendar/eventStatus.js +43 -2
  41. package/dist/esm/integrations/builtin/calendar/eventStatus.js.map +1 -1
  42. package/dist/esm/l10n/en.json.js +4 -1
  43. package/dist/esm/l10n/en.json.js.map +1 -1
  44. package/dist/esm/l10n/nl.json.js +5 -2
  45. package/dist/esm/l10n/nl.json.js.map +1 -1
  46. package/dist/esm/library-style.js +1 -1
  47. package/dist/esm/nextcloud-vue.css +623 -362
  48. package/dist/nextcloud-vue.cjs.js +894 -720
  49. package/dist/nextcloud-vue.cjs.js.map +2 -2
  50. package/dist/nextcloud-vue.css +623 -362
  51. package/l10n/en.json +4 -1
  52. package/l10n/nl.json +5 -2
  53. package/package.json +1 -1
  54. package/src/components/CnActionDialog/CnActionDialog.vue +17 -4
  55. package/src/components/CnConversationThread/CnConversationThread.vue +16 -2
  56. package/src/components/CnConversationThread/CnConversationWidget.vue +5 -1
  57. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +47 -2
  58. package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
  59. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +15 -1
  60. package/src/components/CnPlanWidget/CnPlanWidgetRow.vue +17 -2
  61. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +45 -2
  62. package/src/components/CnRetentionWidget/CnRetentionWidget.vue +8 -1
  63. package/src/components/CnTimelineWidget/CnTimelineManage.vue +1 -1
  64. package/src/css/dialog.css +6 -0
  65. package/src/css/look-board-detail.css +137 -0
  66. package/src/css/look-board.css +78 -2
  67. package/src/integrations/builtin/calendar/eventStatus.js +42 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CnConversationThread.vue3.js","sources":["../../../../src/components/CnConversationThread/CnConversationThread.vue?vue&type=template&id=e2600a68&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<section\n\t\tclass=\"cn-conversation-thread\"\n\t\tdata-testid=\"cn-conversation-thread\"\n\t\t:aria-labelledby=\"title ? titleId : null\"\n\t\t:aria-label=\"title ? null : fallbackLabel\">\n\t\t<div v-if=\"title || $slots['header-actions']\" class=\"cn-conversation-thread__header\">\n\t\t\t<div v-if=\"title\" class=\"cn-conversation-thread__heading\">\n\t\t\t\t<component\n\t\t\t\t\t:is=\"titleTag\"\n\t\t\t\t\t:id=\"titleId\"\n\t\t\t\t\tclass=\"cn-conversation-thread__title\">\n\t\t\t\t\t{{ title }}\n\t\t\t\t</component>\n\t\t\t\t<!-- A div, not a <p>: a theme that sets every paragraph's size with\n\t\t\t\t !important would otherwise override the 14px subtitle. -->\n\t\t\t\t<div v-if=\"subtitle\" class=\"cn-conversation-thread__subtitle\" data-testid=\"cn-conversation-subtitle\">\n\t\t\t\t\t{{ subtitle }}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div v-if=\"$slots['header-actions']\" class=\"cn-conversation-thread__header-actions\">\n\t\t\t\t<!-- @slot header-actions Buttons beside the title, for example \"Log contact\". -->\n\t\t\t\t<slot name=\"header-actions\" />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<CnQuickFilterBar\n\t\t\tv-if=\"channelChips.length > 0\"\n\t\t\tinline\n\t\t\tclass=\"cn-conversation-thread__channels\"\n\t\t\t:tabs=\"channelChips\"\n\t\t\t:activeIndex=\"activeChannelIndex\"\n\t\t\t@update:activeIndex=\"onChannelChip\" />\n\n\t\t<p v-if=\"loading && rows.length === 0\"\n\t\t\tclass=\"cn-conversation-thread__empty\"\n\t\t\trole=\"status\"\n\t\t\tdata-testid=\"cn-conversation-loading\">\n\t\t\t{{ loadingText }}\n\t\t</p>\n\t\t<p v-else-if=\"rows.length === 0\" class=\"cn-conversation-thread__empty\" data-testid=\"cn-conversation-empty\">\n\t\t\t{{ emptyText }}\n\t\t</p>\n\n\t\t<p v-else-if=\"shownRows.length === 0\" class=\"cn-conversation-thread__empty\" data-testid=\"cn-conversation-channel-empty\">\n\t\t\t{{ emptyText }}\n\t\t</p>\n\n\t\t<ol v-else class=\"cn-conversation-thread__messages\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in shownRows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-conversation-thread__message\"\n\t\t\t\t:class=\"`cn-conversation-thread__message--${row.side}`\"\n\t\t\t\tdata-testid=\"cn-conversation-message\"\n\t\t\t\t:data-side=\"row.side\">\n\t\t\t\t<span class=\"cn-conversation-thread__avatar\" aria-hidden=\"true\">{{ row.initials }}</span>\n\t\t\t\t<div class=\"cn-conversation-thread__bubble\">\n\t\t\t\t\t<span class=\"cn-conversation-thread__meta\">\n\t\t\t\t\t\t<span class=\"hidden-visually\">{{ row.directionLabel }}</span>\n\t\t\t\t\t\t<span class=\"cn-conversation-thread__author\">{{ row.author }}</span>\n\t\t\t\t\t\t<span v-if=\"row.channel\" class=\"cn-conversation-thread__channel\" data-testid=\"cn-conversation-channel\">{{ row.channel }}</span>\n\t\t\t\t\t\t<span v-if=\"row.status\" class=\"cn-conversation-thread__status\" data-testid=\"cn-conversation-status\">{{ row.status }}</span>\n\t\t\t\t\t\t<span v-if=\"showDirection\"\n\t\t\t\t\t\t\tclass=\"cn-conversation-thread__direction\"\n\t\t\t\t\t\t\tdata-testid=\"cn-conversation-direction\"\n\t\t\t\t\t\t\taria-hidden=\"true\">{{ row.directionWord }}</span>\n\t\t\t\t\t\t<time v-if=\"row.timeLabel\" :datetime=\"row.datetime || null\">{{ row.timeLabel }}</time>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-conversation-thread__text\">{{ row.text }}</span>\n\t\t\t\t\t<span v-if=\"row.note\" class=\"cn-conversation-thread__note\" data-testid=\"cn-conversation-note\">{{ row.note }}</span>\n\t\t\t\t\t<span v-if=\"row.actions.length > 0\" class=\"cn-conversation-thread__message-actions\">\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-for=\"action in row.actions\"\n\t\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t:disabled=\"action.disabled === true\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-conversation-action-${action.id}`\"\n\t\t\t\t\t\t\t@click=\"$emit('message-action', { action: action.id, message: row.key })\">\n\t\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</li>\n\t\t</ol>\n\n\t\t<form\n\t\t\tv-if=\"allowReply\"\n\t\t\tclass=\"cn-conversation-thread__reply\"\n\t\t\tdata-testid=\"cn-conversation-reply\"\n\t\t\t@submit.prevent=\"onSend\">\n\t\t\t<!-- @slot reply-tools Tools above the reply box, for example a template picker. -->\n\t\t\t<!-- @binding {Function} setDraft Puts a text in the reply box. -->\n\t\t\t<slot name=\"reply-tools\" :setDraft=\"setDraft\" />\n\t\t\t<div class=\"cn-conversation-thread__reply-head\">\n\t\t\t\t<label :for=\"inputId\" class=\"cn-conversation-thread__reply-label\">{{ replyLabel }}</label>\n\t\t\t\t<span v-if=\"replyHint\" class=\"cn-conversation-thread__reply-hint\" data-testid=\"cn-conversation-reply-hint\">{{ replyHint }}</span>\n\t\t\t</div>\n\t\t\t<textarea\n\t\t\t\t:id=\"inputId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-conversation-thread__input\"\n\t\t\t\trows=\"2\"\n\t\t\t\t:placeholder=\"placeholder || null\"\n\t\t\t\t:disabled=\"sending\"\n\t\t\t\t:aria-describedby=\"errorMessage ? errorId : null\"\n\t\t\t\tdata-testid=\"cn-conversation-input\"\n\t\t\t\t@keydown.ctrl.enter.prevent=\"onSend\"\n\t\t\t\t@keydown.meta.enter.prevent=\"onSend\" />\n\t\t\t<p\n\t\t\t\tv-if=\"errorMessage\"\n\t\t\t\t:id=\"errorId\"\n\t\t\t\tclass=\"cn-conversation-thread__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-conversation-error\">\n\t\t\t\t{{ errorMessage }}\n\t\t\t</p>\n\t\t\t<!-- The option at the start and the buttons at the end of one row. -->\n\t\t\t<div class=\"cn-conversation-thread__reply-foot\">\n\t\t\t\t<label v-if=\"optionShown\" class=\"cn-conversation-thread__reply-option\" data-testid=\"cn-conversation-reply-option\">\n\t\t\t\t\t<input v-model=\"optionOn\" type=\"checkbox\" :disabled=\"sending\">\n\t\t\t\t\t<span>{{ replyOption.label }}</span>\n\t\t\t\t</label>\n\t\t\t\t<div class=\"cn-conversation-thread__reply-actions\">\n\t\t\t\t\t<!-- @slot reply-actions Extra buttons before Send, for example \"Save draft\". -->\n\t\t\t\t\t<!-- @binding {string} draft The text in the reply box. -->\n\t\t\t\t\t<slot name=\"reply-actions\" :draft=\"draft\" />\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t:disabled=\"!canSend\"\n\t\t\t\t\t\tdata-testid=\"cn-conversation-send\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Send :size=\"16\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ sendLabel }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</form>\n\t</section>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport Send from 'vue-material-design-icons/Send.vue'\nimport CnQuickFilterBar from '../CnQuickFilterBar/CnQuickFilterBar.vue'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\nlet conversationThreadUid = 0\n\n/**\n * CnConversationThread: the messages between you and the other party, and a box to answer.\n *\n * Each message has an author, a time and a side: `us` for the organisation,\n * `them` for the resident or customer. The reply box emits `send`, and also\n * posts to `endpoint` when one is set. It needs no Talk and no other app:\n * where the messages are stored is the host's business.\n *\n * ```vue\n * <CnConversationThread\n * title=\"Contact with the resident\"\n * reply-label=\"Answer to the resident\"\n * :messages=\"[\n * { id: 1, author: 'Sanne de Vries', time: '2026-10-04T10:52:00', side: 'them',\n * text: 'Thank you. I would like to see all documents.' },\n * { id: 2, time: '2026-10-04T10:24:00', side: 'us',\n * text: 'Construction starts in March.' },\n * ]\"\n * @send=\"saveReply\" />\n * ```\n *\n * The `conversation` detail widget type renders this thread from a field on\n * the record.\n */\nexport default {\n\tname: 'CnConversationThread',\n\n\tcomponents: {\n\t\tCnQuickFilterBar,\n\t\tNcButton,\n\t\tSend,\n\t},\n\n\tinject: {\n\t\t/** The host app's translate, for the All chip in the host's word. */\n\t\tcnTranslate: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The messages, oldest first: `{ id?, author?, time?, text, side?, channel?, status?, actions?, note? }`.\n\t\t * `status` is shown after the channel (\"Failed\"); `actions` are\n\t\t * `{ id, label, disabled? }` buttons under the text, each emitting\n\t\t * `message-action`.\n\t\t * `note` is a muted line under the text.\n\t\t * `side` is `us` or `them` (default `them`). `time` is an ISO\n\t\t * date, or any text to show as is. `channel` is shown after the\n\t\t * author (\"E-mail\", \"Phone note\"); `note` is a muted line under the text.\n\t\t */\n\t\tmessages: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Heading of the thread. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A line under the title, such as \"Oldest first, with the channel of each message\". */\n\t\tsubtitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Say each message's direction in words before its time (\"Incoming · 3 Oct\"), not only to a screen reader. */\n\t\tshowDirection: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Element the heading renders as. */\n\t\ttitleTag: {\n\t\t\ttype: String,\n\t\t\tdefault: 'h3',\n\t\t},\n\n\t\t/** A line beside the reply label saying where the answer goes, such as \"Goes to the message box in the portal\". */\n\t\treplyHint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * A switch under the reply box whose state is sent with the reply:\n\t\t * `{ label, key, value? }`, `value` the starting state (on by default).\n\t\t * The reply's `send` event carries `{ [key]: state }` after the text.\n\t\t *\n\t\t * @type {{label: string, key: string, value?: boolean}|null}\n\t\t */\n\t\treplyOption: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the reply box renders. Turn it off for a closed or read-only record. */\n\t\tallowReply: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Label of the reply box. */\n\t\treplyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Reply'),\n\t\t},\n\n\t\t/** Placeholder inside the reply box. */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Label of the send button. */\n\t\tsendLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Send'),\n\t\t},\n\n\t\t/** Author shown on an `us` message that names none. */\n\t\tusLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'You'),\n\t\t},\n\n\t\t/**\n\t\t * URL the reply is POSTed to as `{ message }`. Empty means the host\n\t\t * handles `send` itself and nothing is requested.\n\t\t */\n\t\tendpoint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Extra fields sent along with `message` when `endpoint` is set. */\n\t\tpayload: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether the messages are still loading; with none yet the thread says so. */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Draw channel chips above the messages: All, then one per channel\n\t\t * with its count. Choosing one shows only that channel's messages.\n\t\t */\n\t\tchannelFilter: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Channel labels that always get a chip, in this order, also when no\n\t\t * message uses them yet. Channels the messages use follow.\n\t\t */\n\t\tchannels: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Shown when there are no messages yet. */\n\t\temptyText: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No messages yet.'),\n\t\t},\n\t},\n\n\temits: [\n\t\t/** A reply was submitted. Payload: the text. */\n\t\t'send',\n\t\t/** The endpoint accepted the reply. Payload: the response body. */\n\t\t'sent',\n\t\t/** The endpoint refused the reply. Payload: the error. */\n\t\t'error',\n\t\t/** A message action was pressed. Payload: `{ action, message }`, the action id and the message key. */\n\t\t'message-action',\n\t],\n\n\tdata() {\n\t\tconversationThreadUid += 1\n\t\treturn {\n\t\t\tdraft: '',\n\t\t\t/** The state of the reply option's switch. */\n\t\t\toptionOn: this.replyOption?.value !== false,\n\t\t\t/** The channel the chips narrow the thread to; '' is All. */\n\t\t\tactiveChannel: '',\n\t\t\tsending: false,\n\t\t\terrorMessage: '',\n\t\t\ttitleId: `cn-conversation-title-${conversationThreadUid}`,\n\t\t\tinputId: `cn-conversation-input-${conversationThreadUid}`,\n\t\t\terrorId: `cn-conversation-error-${conversationThreadUid}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The messages, with author, side, time and initials resolved.\n\t\t *\n\t\t * @return {Array<{key: string, author: string, initials: string, side: string, text: string, timeLabel: string, datetime: string, channel: string, directionLabel: string, directionWord: string, note: string}>} The rows.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\trows() {\n\t\t\treturn (Array.isArray(this.messages) ? this.messages : [])\n\t\t\t\t.filter((message) => message && typeof message === 'object')\n\t\t\t\t.map((message, index) => {\n\t\t\t\t\tconst side = message.side === 'us' ? 'us' : 'them'\n\t\t\t\t\tconst author = typeof message.author === 'string' && message.author !== ''\n\t\t\t\t\t\t? message.author\n\t\t\t\t\t\t: (side === 'us' ? this.usLabel : '')\n\t\t\t\t\tconst time = this.formatTime(message.time)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey: message.id === undefined || message.id === null ? `message-${index}` : String(message.id),\n\t\t\t\t\t\tauthor,\n\t\t\t\t\t\tinitials: this.initialsOf(author),\n\t\t\t\t\t\tside,\n\t\t\t\t\t\ttext: message.text === undefined || message.text === null ? '' : String(message.text),\n\t\t\t\t\t\ttimeLabel: time.label,\n\t\t\t\t\t\tdatetime: time.datetime,\n\t\t\t\t\t\tchannel: typeof message.channel === 'string' ? message.channel : '',\n\t\t\t\t\t\tstatus: typeof message.status === 'string' ? message.status : '',\n\t\t\t\t\t\tactions: Array.isArray(message.actions) ? message.actions.filter((action) => action && action.id && action.label) : [],\n\t\t\t\t\t\tdirectionLabel: side === 'us' ? t('nextcloud-vue', 'Sent message') : t('nextcloud-vue', 'Received message'),\n\t\t\t\t\t\tdirectionWord: side === 'us' ? t('nextcloud-vue', 'Outgoing') : t('nextcloud-vue', 'Incoming'),\n\t\t\t\t\t\tnote: typeof message.note === 'string' ? message.note : '',\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The channel labels with a chip: the declared ones, then the ones\n\t\t * the messages use.\n\t\t *\n\t\t * @return {Array<string>} The labels, each once.\n\t\t */\n\t\tchannelLabels() {\n\t\t\tconst declared = (Array.isArray(this.channels) ? this.channels : []).filter((label) => typeof label === 'string' && label !== '')\n\t\t\treturn [...new Set([...declared, ...this.rows.map((row) => row.channel).filter(Boolean)])]\n\t\t},\n\n\t\t/**\n\t\t * The chips: All, then each channel, each with its count. Empty\n\t\t * without `channelFilter` or without channels.\n\t\t *\n\t\t * @return {Array<{label: string, count: number}>} The chips.\n\t\t */\n\t\tchannelChips() {\n\t\t\tif (!this.channelFilter || this.channelLabels.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn [\n\t\t\t\t{ label: this.allLabel, count: this.rows.length },\n\t\t\t\t...this.channelLabels.map((label) => ({ label, count: this.rows.filter((row) => row.channel === label).length })),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * Whether the reply option renders: it has a label and a key.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/conversation-reply-option/specs/conversation-source/spec.md#requirement-a-reply-can-carry-a-hint-and-an-option\n\t\t */\n\t\toptionShown() {\n\t\t\tconst option = this.replyOption\n\t\t\treturn Boolean(option && typeof option.label === 'string' && option.label !== '' && typeof option.key === 'string' && option.key !== '')\n\t\t},\n\n\t\t/**\n\t\t * What travels with the reply besides its text.\n\t\t *\n\t\t * @return {object} `{ [key]: state }`, or {} without an option.\n\t\t * @spec openspec/changes/conversation-reply-option/specs/conversation-source/spec.md#requirement-a-reply-can-carry-a-hint-and-an-option\n\t\t */\n\t\treplyExtras() {\n\t\t\treturn this.optionShown ? { [this.replyOption.key]: this.optionOn === true } : {}\n\t\t},\n\n\t\t/**\n\t\t * The All chip: the host's word first, as its own filter chips read\n\t\t * (\"Alles\"), then the library's.\n\t\t *\n\t\t * @return {string} The label.\n\t\t * @spec openspec/changes/conversation-all-chip-host-word/specs/conversation-source/spec.md#requirement-the-all-chip-reads-the-hosts-word\n\t\t */\n\t\tallLabel() {\n\t\t\tconst host = typeof this.cnTranslate === 'function' ? this.cnTranslate('All') : 'All'\n\t\t\treturn typeof host === 'string' && host !== '' && host !== 'All' ? host : t('nextcloud-vue', 'All')\n\t\t},\n\n\t\t/** @return {number} The pressed chip: 0 for All. */\n\t\tactiveChannelIndex() {\n\t\t\tconst index = this.channelLabels.indexOf(this.activeChannel)\n\t\t\treturn index < 0 ? 0 : index + 1\n\t\t},\n\n\t\t/** @return {Array<object>} The rows on the chosen channel, or all of them. */\n\t\tshownRows() {\n\t\t\tif (this.channelChips.length === 0 || this.activeChannelIndex === 0) {\n\t\t\t\treturn this.rows\n\t\t\t}\n\t\t\treturn this.rows.filter((row) => row.channel === this.activeChannel)\n\t\t},\n\n\t\t/**\n\t\t * Whether there is something to send and nothing in flight.\n\t\t *\n\t\t * @return {boolean} True when Send is enabled.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tcanSend() {\n\t\t\treturn !this.sending && this.draft.trim() !== ''\n\t\t},\n\n\t\t/**\n\t\t * Accessible name for a thread without a title.\n\t\t *\n\t\t * @return {string} The label.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tfallbackLabel() {\n\t\t\treturn t('nextcloud-vue', 'Conversation')\n\t\t},\n\n\t\t/** @return {string} What the thread says while its messages load. */\n\t\tloadingText() {\n\t\t\treturn t('nextcloud-vue', 'Loading messages…')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Put a text in the reply box (a template a host tool picked).\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {void}\n\t\t */\n\t\tsetDraft(text) {\n\t\t\tthis.draft = typeof text === 'string' ? text : ''\n\t\t},\n\n\t\t/**\n\t\t * Narrow the thread to the chip's channel; the All chip (0) clears it.\n\t\t *\n\t\t * @param {number|null} index The chip index.\n\t\t * @return {void}\n\t\t */\n\t\tonChannelChip(index) {\n\t\t\tthis.activeChannel = index > 0 ? (this.channelLabels[index - 1] || '') : ''\n\t\t},\n\n\t\t/**\n\t\t * Up to two initials of a name, for the avatar.\n\t\t *\n\t\t * @param {string} name The author.\n\t\t * @return {string} The initials, upper case.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tinitialsOf(name) {\n\t\t\tconst parts = String(name || '').trim().split(/\\s+/).filter(Boolean)\n\t\t\tif (parts.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst first = parts[0].charAt(0)\n\t\t\tconst last = parts.length > 1 ? parts[parts.length - 1].charAt(0) : ''\n\t\t\treturn (first + last).toUpperCase()\n\t\t},\n\n\t\t/**\n\t\t * Turn a message time into what the reader sees and what `<time>` carries.\n\t\t *\n\t\t * @param {unknown} value An ISO date, a Date, or text to show as is.\n\t\t * @return {{label: string, datetime: string}} The visible label and the machine value.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tformatTime(value) {\n\t\t\tif (value === null || value === undefined || value === '') {\n\t\t\t\treturn { label: '', datetime: '' }\n\t\t\t}\n\t\t\tconst date = value instanceof Date ? value : new Date(value)\n\t\t\tconst looksLikeDate = value instanceof Date || typeof value === 'number' || /^\\d{4}-\\d{2}-\\d{2}/.test(String(value))\n\t\t\tif (!looksLikeDate || Number.isNaN(date.getTime())) {\n\t\t\t\treturn { label: String(value), datetime: '' }\n\t\t\t}\n\t\t\tconst label = date.toLocaleString(userLocale(), { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })\n\t\t\treturn { label, datetime: date.toISOString() }\n\t\t},\n\n\t\t/**\n\t\t * Submit the reply: tell the host, and post it when an endpoint is set.\n\t\t *\n\t\t * Without an endpoint the box clears straight away, because the host\n\t\t * owns the send. With one it clears only when the request succeeds, so\n\t\t * a refused reply is still there to try again.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tasync onSend() {\n\t\t\tif (!this.canSend) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst text = this.draft.trim()\n\t\t\tthis.errorMessage = ''\n\t\t\tthis.$emit('send', text, this.replyExtras)\n\t\t\tif (!this.endpoint) {\n\t\t\t\tthis.draft = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.sending = true\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.endpoint), { ...this.payload, ...this.replyExtras, message: text })\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.$emit('sent', response?.data)\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'The message could not be sent. Try again.')\n\t\t\t\tthis.$emit('error', error)\n\t\t\t} finally {\n\t\t\t\tthis.sending = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-conversation-thread {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(3.5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__status {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: 700;\n}\n\n.cn-conversation-thread__message-actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2 * var(--default-grid-baseline));\n\tmargin-top: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__header {\n\talign-items: flex-start;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(3 * var(--default-grid-baseline));\n\tjustify-content: space-between;\n}\n\n.cn-conversation-thread__header-actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__title {\n\tfont-size: 1.1em;\n\tfont-weight: 700;\n\tmargin: 0;\n}\n\n.cn-conversation-thread__heading {\n\tdisplay: flex;\n\tflex: 1 1 260px;\n\tflex-direction: column;\n\tgap: 3px;\n\tmin-width: 0;\n}\n\n.cn-conversation-thread__subtitle {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tline-height: normal;\n\tmargin: 0;\n}\n\n.cn-conversation-thread__direction,\n.cn-conversation-thread__meta time {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-conversation-thread__direction::after {\n\tcontent: ' ·';\n}\n\n.cn-conversation-thread__note {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-conversation-thread__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin: 0;\n}\n\n.cn-conversation-thread__messages {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(3.5 * var(--default-grid-baseline));\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-conversation-thread__message {\n\tdisplay: flex;\n\tgap: calc(3 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__message--us {\n\tflex-direction: row-reverse;\n}\n\n.cn-conversation-thread__avatar {\n\talign-items: center;\n\tbackground: var(--color-background-dark);\n\tborder-radius: 50%;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: none;\n\tfont-size: 0.8em;\n\tfont-weight: 700;\n\theight: 34px;\n\tjustify-content: center;\n\twidth: 34px;\n}\n\n.cn-conversation-thread__bubble {\n\tbackground: var(--color-background-hover);\n\tborder-radius: var(--border-radius-large);\n\tborder-start-start-radius: var(--border-radius-small, 4px);\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: 1;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline);\n\tmin-width: 0;\n\tpadding: calc(3 * var(--default-grid-baseline)) calc(3.5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__message--us .cn-conversation-thread__bubble {\n\tbackground: var(--color-primary-element-light);\n\tborder-start-end-radius: var(--border-radius-small, 4px);\n\tborder-start-start-radius: var(--border-radius-large);\n\tcolor: var(--color-primary-element-light-text);\n}\n\n.cn-conversation-thread__meta {\n\talign-items: center;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tfont-size: 0.9em;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__author {\n\tfont-weight: 600;\n}\n\n.cn-conversation-thread__text {\n\toverflow-wrap: anywhere;\n\twhite-space: pre-wrap;\n}\n\n.cn-conversation-thread__reply {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__reply-head {\n\talign-items: baseline;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2 * var(--default-grid-baseline));\n\tjustify-content: space-between;\n}\n\n.cn-conversation-thread__reply-label {\n\tfont-weight: 600;\n}\n\n.cn-conversation-thread__reply-hint {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-conversation-thread__reply-option {\n\talign-items: center;\n\tdisplay: flex;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__input {\n\tbox-sizing: border-box;\n\tmargin: 0;\n\tresize: vertical;\n\twidth: 100%;\n}\n\n.cn-conversation-thread__error {\n\tcolor: var(--color-error-text, var(--color-error));\n\tmargin: 0;\n}\n\n.cn-conversation-thread__reply-foot {\n\talign-items: center;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2.5 * var(--default-grid-baseline));\n\tjustify-content: space-between;\n}\n\n.cn-conversation-thread__reply-actions {\n\tmargin-inline-start: auto;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2.5 * var(--default-grid-baseline));\n\tjustify-content: flex-end;\n}\n\n.cn-conversation-thread__channel {\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_createElementBlock","_openBlock","_createBlock","_resolveDynamicComponent","_toDisplayString","_renderSlot","_Fragment","_renderList","_normalizeClass","_createElementVNode","_createTextVNode","_createVNode"],"mappings":"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"}
1
+ {"version":3,"file":"CnConversationThread.vue3.js","sources":["../../../../src/components/CnConversationThread/CnConversationThread.vue?vue&type=template&id=40f702bd&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<section\n\t\tclass=\"cn-conversation-thread\"\n\t\tdata-testid=\"cn-conversation-thread\"\n\t\t:aria-labelledby=\"title ? titleId : null\"\n\t\t:aria-label=\"title ? null : fallbackLabel\">\n\t\t<div v-if=\"title || $slots['header-actions']\" class=\"cn-conversation-thread__header\">\n\t\t\t<div v-if=\"title\" class=\"cn-conversation-thread__heading\">\n\t\t\t\t<component\n\t\t\t\t\t:is=\"titleTag\"\n\t\t\t\t\t:id=\"titleId\"\n\t\t\t\t\tclass=\"cn-conversation-thread__title\">\n\t\t\t\t\t{{ title }}\n\t\t\t\t</component>\n\t\t\t\t<!-- A div, not a <p>: a theme that sets every paragraph's size with\n\t\t\t\t !important would otherwise override the 14px subtitle. -->\n\t\t\t\t<div v-if=\"subtitle\" class=\"cn-conversation-thread__subtitle\" data-testid=\"cn-conversation-subtitle\">\n\t\t\t\t\t{{ subtitle }}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div v-if=\"$slots['header-actions']\" class=\"cn-conversation-thread__header-actions\">\n\t\t\t\t<!-- @slot header-actions Buttons beside the title, for example \"Log contact\". -->\n\t\t\t\t<slot name=\"header-actions\" />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<CnQuickFilterBar\n\t\t\tv-if=\"channelChips.length > 0\"\n\t\t\tinline\n\t\t\tclass=\"cn-conversation-thread__channels\"\n\t\t\t:tabs=\"channelChips\"\n\t\t\t:activeIndex=\"activeChannelIndex\"\n\t\t\t@update:activeIndex=\"onChannelChip\" />\n\n\t\t<p v-if=\"loading && rows.length === 0\"\n\t\t\tclass=\"cn-conversation-thread__empty\"\n\t\t\trole=\"status\"\n\t\t\tdata-testid=\"cn-conversation-loading\">\n\t\t\t{{ loadingText }}\n\t\t</p>\n\t\t<p v-else-if=\"rows.length === 0\" class=\"cn-conversation-thread__empty\" data-testid=\"cn-conversation-empty\">\n\t\t\t{{ emptyText }}\n\t\t</p>\n\n\t\t<p v-else-if=\"shownRows.length === 0\" class=\"cn-conversation-thread__empty\" data-testid=\"cn-conversation-channel-empty\">\n\t\t\t{{ emptyText }}\n\t\t</p>\n\n\t\t<ol v-else class=\"cn-conversation-thread__messages\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in shownRows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-conversation-thread__message\"\n\t\t\t\t:class=\"`cn-conversation-thread__message--${row.side}`\"\n\t\t\t\tdata-testid=\"cn-conversation-message\"\n\t\t\t\t:data-side=\"row.side\">\n\t\t\t\t<span class=\"cn-conversation-thread__avatar\" aria-hidden=\"true\">{{ row.initials }}</span>\n\t\t\t\t<div class=\"cn-conversation-thread__bubble\">\n\t\t\t\t\t<span class=\"cn-conversation-thread__meta\">\n\t\t\t\t\t\t<span class=\"hidden-visually\">{{ row.directionLabel }}</span>\n\t\t\t\t\t\t<span class=\"cn-conversation-thread__author\">{{ row.author }}</span>\n\t\t\t\t\t\t<span v-if=\"row.channel\" class=\"cn-conversation-thread__channel\" data-testid=\"cn-conversation-channel\"><CnIcon v-if=\"row.channelIcon\"\n\t\t\t\t\t\t\tclass=\"cn-conversation-thread__channel-icon\"\n\t\t\t\t\t\t\t:name=\"row.channelIcon\"\n\t\t\t\t\t\t\t:size=\"13\"\n\t\t\t\t\t\t\taria-hidden=\"true\" />{{ row.channel }}</span>\n\t\t\t\t\t\t<span v-if=\"row.status\" class=\"cn-conversation-thread__status\" data-testid=\"cn-conversation-status\">{{ row.status }}</span>\n\t\t\t\t\t\t<span v-if=\"showDirection\"\n\t\t\t\t\t\t\tclass=\"cn-conversation-thread__direction\"\n\t\t\t\t\t\t\tdata-testid=\"cn-conversation-direction\"\n\t\t\t\t\t\t\taria-hidden=\"true\">{{ row.directionWord }}</span>\n\t\t\t\t\t\t<time v-if=\"row.timeLabel\" :datetime=\"row.datetime || null\">{{ row.timeLabel }}</time>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-conversation-thread__text\">{{ row.text }}</span>\n\t\t\t\t\t<span v-if=\"row.note\" class=\"cn-conversation-thread__note\" data-testid=\"cn-conversation-note\">{{ row.note }}</span>\n\t\t\t\t\t<span v-if=\"row.actions.length > 0\" class=\"cn-conversation-thread__message-actions\">\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-for=\"action in row.actions\"\n\t\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t:disabled=\"action.disabled === true\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-conversation-action-${action.id}`\"\n\t\t\t\t\t\t\t@click=\"$emit('message-action', { action: action.id, message: row.key })\">\n\t\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</li>\n\t\t</ol>\n\n\t\t<form\n\t\t\tv-if=\"allowReply\"\n\t\t\tclass=\"cn-conversation-thread__reply\"\n\t\t\tdata-testid=\"cn-conversation-reply\"\n\t\t\t@submit.prevent=\"onSend\">\n\t\t\t<!-- @slot reply-tools Tools above the reply box, for example a template picker. -->\n\t\t\t<!-- @binding {Function} setDraft Puts a text in the reply box. -->\n\t\t\t<slot name=\"reply-tools\" :setDraft=\"setDraft\" />\n\t\t\t<div class=\"cn-conversation-thread__reply-head\">\n\t\t\t\t<label :for=\"inputId\" class=\"cn-conversation-thread__reply-label\">{{ replyLabel }}</label>\n\t\t\t\t<span v-if=\"replyHint\" class=\"cn-conversation-thread__reply-hint\" data-testid=\"cn-conversation-reply-hint\">{{ replyHint }}</span>\n\t\t\t</div>\n\t\t\t<textarea\n\t\t\t\t:id=\"inputId\"\n\t\t\t\tv-model=\"draft\"\n\t\t\t\tclass=\"cn-conversation-thread__input\"\n\t\t\t\trows=\"2\"\n\t\t\t\t:placeholder=\"placeholder || null\"\n\t\t\t\t:disabled=\"sending\"\n\t\t\t\t:aria-describedby=\"errorMessage ? errorId : null\"\n\t\t\t\tdata-testid=\"cn-conversation-input\"\n\t\t\t\t@keydown.ctrl.enter.prevent=\"onSend\"\n\t\t\t\t@keydown.meta.enter.prevent=\"onSend\" />\n\t\t\t<p\n\t\t\t\tv-if=\"errorMessage\"\n\t\t\t\t:id=\"errorId\"\n\t\t\t\tclass=\"cn-conversation-thread__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-conversation-error\">\n\t\t\t\t{{ errorMessage }}\n\t\t\t</p>\n\t\t\t<!-- The option at the start and the buttons at the end of one row. -->\n\t\t\t<div class=\"cn-conversation-thread__reply-foot\">\n\t\t\t\t<label v-if=\"optionShown\" class=\"cn-conversation-thread__reply-option\" data-testid=\"cn-conversation-reply-option\">\n\t\t\t\t\t<input v-model=\"optionOn\" type=\"checkbox\" :disabled=\"sending\">\n\t\t\t\t\t<span>{{ replyOption.label }}</span>\n\t\t\t\t</label>\n\t\t\t\t<div class=\"cn-conversation-thread__reply-actions\">\n\t\t\t\t\t<!-- @slot reply-actions Extra buttons before Send, for example \"Save draft\". -->\n\t\t\t\t\t<!-- @binding {string} draft The text in the reply box. -->\n\t\t\t\t\t<slot name=\"reply-actions\" :draft=\"draft\" />\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t:disabled=\"!canSend\"\n\t\t\t\t\t\tdata-testid=\"cn-conversation-send\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Send :size=\"16\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ sendLabel }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</form>\n\t</section>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport Send from 'vue-material-design-icons/Send.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport CnQuickFilterBar from '../CnQuickFilterBar/CnQuickFilterBar.vue'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\nlet conversationThreadUid = 0\n\n/**\n * CnConversationThread: the messages between you and the other party, and a box to answer.\n *\n * Each message has an author, a time and a side: `us` for the organisation,\n * `them` for the resident or customer. The reply box emits `send`, and also\n * posts to `endpoint` when one is set. It needs no Talk and no other app:\n * where the messages are stored is the host's business.\n *\n * ```vue\n * <CnConversationThread\n * title=\"Contact with the resident\"\n * reply-label=\"Answer to the resident\"\n * :messages=\"[\n * { id: 1, author: 'Sanne de Vries', time: '2026-10-04T10:52:00', side: 'them',\n * text: 'Thank you. I would like to see all documents.' },\n * { id: 2, time: '2026-10-04T10:24:00', side: 'us',\n * text: 'Construction starts in March.' },\n * ]\"\n * @send=\"saveReply\" />\n * ```\n *\n * The `conversation` detail widget type renders this thread from a field on\n * the record.\n */\nexport default {\n\tname: 'CnConversationThread',\n\n\tcomponents: {\n\t\tCnIcon,\n\t\tCnQuickFilterBar,\n\t\tNcButton,\n\t\tSend,\n\t},\n\n\tinject: {\n\t\t/** The host app's translate, for the All chip in the host's word. */\n\t\tcnTranslate: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The messages, oldest first: `{ id?, author?, time?, text, side?, channel?, channelIcon?, status?, actions?, note? }`.\n\t\t * `status` is shown after the channel (\"Failed\"); `actions` are\n\t\t * `{ id, label, disabled? }` buttons under the text, each emitting\n\t\t * `message-action`.\n\t\t * `note` is a muted line under the text.\n\t\t * `side` is `us` or `them` (default `them`). `time` is an ISO\n\t\t * date, or any text to show as is. `channel` is shown after the\n\t\t * author (\"E-mail\", \"Phone note\"); `note` is a muted line under the text.\n\t\t */\n\t\tmessages: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Heading of the thread. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A line under the title, such as \"Oldest first, with the channel of each message\". */\n\t\tsubtitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Say each message's direction in words before its time (\"Incoming · 3 Oct\"), not only to a screen reader. */\n\t\tshowDirection: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Element the heading renders as. */\n\t\ttitleTag: {\n\t\t\ttype: String,\n\t\t\tdefault: 'h3',\n\t\t},\n\n\t\t/** A line beside the reply label saying where the answer goes, such as \"Goes to the message box in the portal\". */\n\t\treplyHint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * A switch under the reply box whose state is sent with the reply:\n\t\t * `{ label, key, value? }`, `value` the starting state (on by default).\n\t\t * The reply's `send` event carries `{ [key]: state }` after the text.\n\t\t *\n\t\t * @type {{label: string, key: string, value?: boolean}|null}\n\t\t */\n\t\treplyOption: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the reply box renders. Turn it off for a closed or read-only record. */\n\t\tallowReply: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Label of the reply box. */\n\t\treplyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Reply'),\n\t\t},\n\n\t\t/** Placeholder inside the reply box. */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Label of the send button. */\n\t\tsendLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Send'),\n\t\t},\n\n\t\t/** Author shown on an `us` message that names none. */\n\t\tusLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'You'),\n\t\t},\n\n\t\t/**\n\t\t * URL the reply is POSTed to as `{ message }`. Empty means the host\n\t\t * handles `send` itself and nothing is requested.\n\t\t */\n\t\tendpoint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Extra fields sent along with `message` when `endpoint` is set. */\n\t\tpayload: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Whether the messages are still loading; with none yet the thread says so. */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Draw channel chips above the messages: All, then one per channel\n\t\t * with its count. Choosing one shows only that channel's messages.\n\t\t */\n\t\tchannelFilter: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Channel labels that always get a chip, in this order, also when no\n\t\t * message uses them yet. Channels the messages use follow.\n\t\t */\n\t\tchannels: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Shown when there are no messages yet. */\n\t\temptyText: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No messages yet.'),\n\t\t},\n\t},\n\n\temits: [\n\t\t/** A reply was submitted. Payload: the text. */\n\t\t'send',\n\t\t/** The endpoint accepted the reply. Payload: the response body. */\n\t\t'sent',\n\t\t/** The endpoint refused the reply. Payload: the error. */\n\t\t'error',\n\t\t/** A message action was pressed. Payload: `{ action, message }`, the action id and the message key. */\n\t\t'message-action',\n\t],\n\n\tdata() {\n\t\tconversationThreadUid += 1\n\t\treturn {\n\t\t\tdraft: '',\n\t\t\t/** The state of the reply option's switch. */\n\t\t\toptionOn: this.replyOption?.value !== false,\n\t\t\t/** The channel the chips narrow the thread to; '' is All. */\n\t\t\tactiveChannel: '',\n\t\t\tsending: false,\n\t\t\terrorMessage: '',\n\t\t\ttitleId: `cn-conversation-title-${conversationThreadUid}`,\n\t\t\tinputId: `cn-conversation-input-${conversationThreadUid}`,\n\t\t\terrorId: `cn-conversation-error-${conversationThreadUid}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The messages, with author, side, time and initials resolved.\n\t\t *\n\t\t * @return {Array<{key: string, author: string, initials: string, side: string, text: string, timeLabel: string, datetime: string, channel: string, directionLabel: string, directionWord: string, note: string}>} The rows.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\trows() {\n\t\t\treturn (Array.isArray(this.messages) ? this.messages : [])\n\t\t\t\t.filter((message) => message && typeof message === 'object')\n\t\t\t\t.map((message, index) => {\n\t\t\t\t\tconst side = message.side === 'us' ? 'us' : 'them'\n\t\t\t\t\tconst author = typeof message.author === 'string' && message.author !== ''\n\t\t\t\t\t\t? message.author\n\t\t\t\t\t\t: (side === 'us' ? this.usLabel : '')\n\t\t\t\t\tconst time = this.formatTime(message.time)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey: message.id === undefined || message.id === null ? `message-${index}` : String(message.id),\n\t\t\t\t\t\tauthor,\n\t\t\t\t\t\tinitials: this.initialsOf(author),\n\t\t\t\t\t\tside,\n\t\t\t\t\t\ttext: message.text === undefined || message.text === null ? '' : String(message.text),\n\t\t\t\t\t\ttimeLabel: time.label,\n\t\t\t\t\t\tdatetime: time.datetime,\n\t\t\t\t\t\tchannel: typeof message.channel === 'string' ? message.channel : '',\n\t\t\t\t\t\tchannelIcon: typeof message.channelIcon === 'string' ? message.channelIcon : '',\n\t\t\t\t\t\tstatus: typeof message.status === 'string' ? message.status : '',\n\t\t\t\t\t\tactions: Array.isArray(message.actions) ? message.actions.filter((action) => action && action.id && action.label) : [],\n\t\t\t\t\t\tdirectionLabel: side === 'us' ? t('nextcloud-vue', 'Sent message') : t('nextcloud-vue', 'Received message'),\n\t\t\t\t\t\tdirectionWord: side === 'us' ? t('nextcloud-vue', 'Outgoing') : t('nextcloud-vue', 'Incoming'),\n\t\t\t\t\t\tnote: typeof message.note === 'string' ? message.note : '',\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The channel labels with a chip: the declared ones, then the ones\n\t\t * the messages use.\n\t\t *\n\t\t * @return {Array<string>} The labels, each once.\n\t\t */\n\t\tchannelLabels() {\n\t\t\tconst declared = (Array.isArray(this.channels) ? this.channels : []).filter((label) => typeof label === 'string' && label !== '')\n\t\t\treturn [...new Set([...declared, ...this.rows.map((row) => row.channel).filter(Boolean)])]\n\t\t},\n\n\t\t/**\n\t\t * The chips: All, then each channel, each with its count. Empty\n\t\t * without `channelFilter` or without channels.\n\t\t *\n\t\t * @return {Array<{label: string, count: number}>} The chips.\n\t\t */\n\t\tchannelChips() {\n\t\t\tif (!this.channelFilter || this.channelLabels.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn [\n\t\t\t\t{ label: this.allLabel, count: this.rows.length },\n\t\t\t\t...this.channelLabels.map((label) => ({ label, count: this.rows.filter((row) => row.channel === label).length })),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * Whether the reply option renders: it has a label and a key.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/conversation-reply-option/specs/conversation-source/spec.md#requirement-a-reply-can-carry-a-hint-and-an-option\n\t\t */\n\t\toptionShown() {\n\t\t\tconst option = this.replyOption\n\t\t\treturn Boolean(option && typeof option.label === 'string' && option.label !== '' && typeof option.key === 'string' && option.key !== '')\n\t\t},\n\n\t\t/**\n\t\t * What travels with the reply besides its text.\n\t\t *\n\t\t * @return {object} `{ [key]: state }`, or {} without an option.\n\t\t * @spec openspec/changes/conversation-reply-option/specs/conversation-source/spec.md#requirement-a-reply-can-carry-a-hint-and-an-option\n\t\t */\n\t\treplyExtras() {\n\t\t\treturn this.optionShown ? { [this.replyOption.key]: this.optionOn === true } : {}\n\t\t},\n\n\t\t/**\n\t\t * The All chip: the host's word first, as its own filter chips read\n\t\t * (\"Alles\"), then the library's.\n\t\t *\n\t\t * @return {string} The label.\n\t\t * @spec openspec/changes/conversation-all-chip-host-word/specs/conversation-source/spec.md#requirement-the-all-chip-reads-the-hosts-word\n\t\t */\n\t\tallLabel() {\n\t\t\tconst host = typeof this.cnTranslate === 'function' ? this.cnTranslate('All') : 'All'\n\t\t\treturn typeof host === 'string' && host !== '' && host !== 'All' ? host : t('nextcloud-vue', 'All')\n\t\t},\n\n\t\t/** @return {number} The pressed chip: 0 for All. */\n\t\tactiveChannelIndex() {\n\t\t\tconst index = this.channelLabels.indexOf(this.activeChannel)\n\t\t\treturn index < 0 ? 0 : index + 1\n\t\t},\n\n\t\t/** @return {Array<object>} The rows on the chosen channel, or all of them. */\n\t\tshownRows() {\n\t\t\tif (this.channelChips.length === 0 || this.activeChannelIndex === 0) {\n\t\t\t\treturn this.rows\n\t\t\t}\n\t\t\treturn this.rows.filter((row) => row.channel === this.activeChannel)\n\t\t},\n\n\t\t/**\n\t\t * Whether there is something to send and nothing in flight.\n\t\t *\n\t\t * @return {boolean} True when Send is enabled.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tcanSend() {\n\t\t\treturn !this.sending && this.draft.trim() !== ''\n\t\t},\n\n\t\t/**\n\t\t * Accessible name for a thread without a title.\n\t\t *\n\t\t * @return {string} The label.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tfallbackLabel() {\n\t\t\treturn t('nextcloud-vue', 'Conversation')\n\t\t},\n\n\t\t/** @return {string} What the thread says while its messages load. */\n\t\tloadingText() {\n\t\t\treturn t('nextcloud-vue', 'Loading messages…')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Put a text in the reply box (a template a host tool picked).\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {void}\n\t\t */\n\t\tsetDraft(text) {\n\t\t\tthis.draft = typeof text === 'string' ? text : ''\n\t\t},\n\n\t\t/**\n\t\t * Narrow the thread to the chip's channel; the All chip (0) clears it.\n\t\t *\n\t\t * @param {number|null} index The chip index.\n\t\t * @return {void}\n\t\t */\n\t\tonChannelChip(index) {\n\t\t\tthis.activeChannel = index > 0 ? (this.channelLabels[index - 1] || '') : ''\n\t\t},\n\n\t\t/**\n\t\t * Up to two initials of a name, for the avatar.\n\t\t *\n\t\t * @param {string} name The author.\n\t\t * @return {string} The initials, upper case.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tinitialsOf(name) {\n\t\t\tconst parts = String(name || '').trim().split(/\\s+/).filter(Boolean)\n\t\t\tif (parts.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst first = parts[0].charAt(0)\n\t\t\tconst last = parts.length > 1 ? parts[parts.length - 1].charAt(0) : ''\n\t\t\treturn (first + last).toUpperCase()\n\t\t},\n\n\t\t/**\n\t\t * Turn a message time into what the reader sees and what `<time>` carries.\n\t\t *\n\t\t * @param {unknown} value An ISO date, a Date, or text to show as is.\n\t\t * @return {{label: string, datetime: string}} The visible label and the machine value.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tformatTime(value) {\n\t\t\tif (value === null || value === undefined || value === '') {\n\t\t\t\treturn { label: '', datetime: '' }\n\t\t\t}\n\t\t\tconst date = value instanceof Date ? value : new Date(value)\n\t\t\tconst looksLikeDate = value instanceof Date || typeof value === 'number' || /^\\d{4}-\\d{2}-\\d{2}/.test(String(value))\n\t\t\tif (!looksLikeDate || Number.isNaN(date.getTime())) {\n\t\t\t\treturn { label: String(value), datetime: '' }\n\t\t\t}\n\t\t\tconst label = date.toLocaleString(userLocale(), { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })\n\t\t\treturn { label, datetime: date.toISOString() }\n\t\t},\n\n\t\t/**\n\t\t * Submit the reply: tell the host, and post it when an endpoint is set.\n\t\t *\n\t\t * Without an endpoint the box clears straight away, because the host\n\t\t * owns the send. With one it clears only when the request succeeds, so\n\t\t * a refused reply is still there to try again.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tasync onSend() {\n\t\t\tif (!this.canSend) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst text = this.draft.trim()\n\t\t\tthis.errorMessage = ''\n\t\t\tthis.$emit('send', text, this.replyExtras)\n\t\t\tif (!this.endpoint) {\n\t\t\t\tthis.draft = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.sending = true\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.endpoint), { ...this.payload, ...this.replyExtras, message: text })\n\t\t\t\tthis.draft = ''\n\t\t\t\tthis.$emit('sent', response?.data)\n\t\t\t} catch (error) {\n\t\t\t\tthis.errorMessage = t('nextcloud-vue', 'The message could not be sent. Try again.')\n\t\t\t\tthis.$emit('error', error)\n\t\t\t} finally {\n\t\t\t\tthis.sending = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-conversation-thread {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(3.5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__status {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: 700;\n}\n\n.cn-conversation-thread__message-actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2 * var(--default-grid-baseline));\n\tmargin-top: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__header {\n\talign-items: flex-start;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(3 * var(--default-grid-baseline));\n\tjustify-content: space-between;\n}\n\n.cn-conversation-thread__header-actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__title {\n\tfont-size: 1.1em;\n\tfont-weight: 700;\n\tmargin: 0;\n}\n\n.cn-conversation-thread__heading {\n\tdisplay: flex;\n\tflex: 1 1 260px;\n\tflex-direction: column;\n\tgap: 3px;\n\tmin-width: 0;\n}\n\n.cn-conversation-thread__subtitle {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tline-height: normal;\n\tmargin: 0;\n}\n\n.cn-conversation-thread__direction,\n.cn-conversation-thread__meta time {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-conversation-thread__direction::after {\n\tcontent: ' ·';\n}\n\n.cn-conversation-thread__note {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-conversation-thread__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin: 0;\n}\n\n.cn-conversation-thread__messages {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(3.5 * var(--default-grid-baseline));\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-conversation-thread__message {\n\tdisplay: flex;\n\tgap: calc(3 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__message--us {\n\tflex-direction: row-reverse;\n}\n\n.cn-conversation-thread__avatar {\n\talign-items: center;\n\tbackground: var(--color-background-dark);\n\tborder-radius: 50%;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: none;\n\tfont-size: 0.8em;\n\tfont-weight: 700;\n\theight: 34px;\n\tjustify-content: center;\n\twidth: 34px;\n}\n\n.cn-conversation-thread__bubble {\n\tbackground: var(--color-background-hover);\n\tborder-radius: var(--border-radius-large);\n\tborder-start-start-radius: var(--border-radius-small, 4px);\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: 1;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline);\n\tmin-width: 0;\n\tpadding: calc(3 * var(--default-grid-baseline)) calc(3.5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__message--us .cn-conversation-thread__bubble {\n\tbackground: var(--color-primary-element-light);\n\tborder-start-end-radius: var(--border-radius-small, 4px);\n\tborder-start-start-radius: var(--border-radius-large);\n\tcolor: var(--color-primary-element-light-text);\n}\n\n.cn-conversation-thread__meta {\n\talign-items: center;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tfont-size: 0.9em;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__author {\n\tfont-weight: 600;\n}\n\n.cn-conversation-thread__text {\n\toverflow-wrap: anywhere;\n\twhite-space: pre-wrap;\n}\n\n.cn-conversation-thread__reply {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__reply-head {\n\talign-items: baseline;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2 * var(--default-grid-baseline));\n\tjustify-content: space-between;\n}\n\n.cn-conversation-thread__reply-label {\n\tfont-weight: 600;\n}\n\n.cn-conversation-thread__reply-hint {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-conversation-thread__reply-option {\n\talign-items: center;\n\tdisplay: flex;\n\tgap: calc(2 * var(--default-grid-baseline));\n}\n\n.cn-conversation-thread__input {\n\tbox-sizing: border-box;\n\tmargin: 0;\n\tresize: vertical;\n\twidth: 100%;\n}\n\n.cn-conversation-thread__error {\n\tcolor: var(--color-error-text, var(--color-error));\n\tmargin: 0;\n}\n\n.cn-conversation-thread__reply-foot {\n\talign-items: center;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2.5 * var(--default-grid-baseline));\n\tjustify-content: space-between;\n}\n\n.cn-conversation-thread__reply-actions {\n\tmargin-inline-start: auto;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: calc(2.5 * var(--default-grid-baseline));\n\tjustify-content: flex-end;\n}\n\n.cn-conversation-thread__channel {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* The channel's icon (`channelIcon`) stands before its name, 5px apart. */\n.cn-conversation-thread__channel:has(.cn-conversation-thread__channel-icon) {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 5px;\n}\n</style>\n"],"names":["_createElementBlock","_openBlock","_createBlock","_resolveDynamicComponent","_toDisplayString","_renderSlot","_Fragment","_renderList","_normalizeClass","_createElementVNode","_createTextVNode","_createVNode"],"mappings":"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"}
@@ -2,7 +2,7 @@ import script from './CnConversationWidget.vue2.js';
2
2
  import { render } from './CnConversationWidget.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-63984d97";
5
+ script.__scopeId = "data-v-f7f83cfa";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -23,7 +23,8 @@ import { userDisplayName } from '../../utils/userDisplayName.js';
23
23
  * `bodyField`), `timeField` (alias `timestampField`), `authorField` (alias
24
24
  * `senderField`), `sideField` (alias `directionField`) with `usValue` (alias
25
25
  * `outValue`) for the messages the organisation sent, and `channelField` with
26
- * an optional `channelMap` from stored value to label ("email" to "E-mail").
26
+ * an optional `channelMap` from stored value to label ("email" to "E-mail")
27
+ * and `channelIcons` from stored value to an icon name, drawn before the label.
27
28
  *
28
29
  * The reply box posts to `endpoint` (`@objectId` filled in), or runs
29
30
  * `replyAction`, an action descriptor the app decides the meaning of: it is
@@ -208,6 +209,7 @@ var script = {
208
209
  const c = this.content || {};
209
210
  const usValue = String(c.outValue ?? c.usValue ?? 'us');
210
211
  const channelMap = c.channelMap && typeof c.channelMap === 'object' ? c.channelMap : {};
212
+ const channelIcons = c.channelIcons && typeof c.channelIcons === 'object' ? c.channelIcons : {};
211
213
  const statusMap = c.statusMap && typeof c.statusMap === 'object' ? c.statusMap : {};
212
214
  const stored = this.rawMessages()
213
215
  .map(({ message, side, key }, index) => {
@@ -224,6 +226,8 @@ var script = {
224
226
  text: readPath(message, c.bodyField || c.textField || 'text'),
225
227
  side: sideOf,
226
228
  channel: channelKey === '' ? '' : this.tr(Object.hasOwn(channelMap, channelKey) ? channelMap[channelKey] : channelKey),
229
+ // @spec openspec/changes/conversation-channel-icons/specs/conversation-channel-icons/spec.md#requirement-a-messages-channel-can-carry-its-icon
230
+ channelIcon: Object.hasOwn(channelIcons, channelKey) && typeof channelIcons[channelKey] === 'string' ? channelIcons[channelKey] : '',
227
231
  status: statusKey === '' ? '' : this.tr(Object.hasOwn(statusMap, statusKey) ? statusMap[statusKey] : statusKey),
228
232
  actions: this.messageActions
229
233
  .filter((action) => this.actionApplies(action, message))
@@ -1 +1 @@
1
- {"version":3,"file":"CnConversationWidget.vue2.js","sources":["../../../../src/components/CnConversationThread/CnConversationWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-case-widget-card\">\n\t\t<CnConversationThread\n\t\t\tref=\"thread\"\n\t\t\t:messages=\"messages\"\n\t\t\t:title=\"tr(content.title || '')\"\n\t\t\t:subtitle=\"tr(content.subtitle || '')\"\n\t\t\t:showDirection=\"content.showDirection === true\"\n\t\t\t:allowReply=\"content.allowReply !== false\"\n\t\t\t:replyLabel=\"content.replyLabel ? tr(content.replyLabel) : undefined\"\n\t\t\t:placeholder=\"tr(content.placeholder || '')\"\n\t\t\t:sendLabel=\"content.sendLabel ? tr(content.sendLabel) : undefined\"\n\t\t\t:replyHint=\"tr(content.replyHint || '')\"\n\t\t\t:replyOption=\"replyOption\"\n\t\t\t:usLabel=\"content.usLabel ? tr(content.usLabel) : undefined\"\n\t\t\t:endpoint=\"replyAction ? '' : endpoint\"\n\t\t\t:loading=\"loading\"\n\t\t\t:emptyText=\"content.emptyText ? tr(content.emptyText) : undefined\"\n\t\t\t:channelFilter=\"content.channelChips === true\"\n\t\t\t:channels=\"channelLabels\"\n\t\t\t:payload=\"replyValues\"\n\t\t\t@send=\"onSend\"\n\t\t\t@sent=\"onSent\"\n\t\t\t@messageAction=\"onMessageAction\">\n\t\t\t<template v-if=\"templates\" #reply-tools=\"{ setDraft }\">\n\t\t\t\t<CnTemplateSelect\n\t\t\t\t\t:url=\"templates.url\"\n\t\t\t\t\t:params=\"templateParams\"\n\t\t\t\t\t:inputLabel=\"tr(templates.inputLabel || 'Template')\"\n\t\t\t\t\tdata-testid=\"cn-conversation-templates\"\n\t\t\t\t\t@apply=\"applyTemplate($event, setDraft)\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"replyOptions.length > 0 || draftUrl\" #reply-actions=\"{ draft }\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\tv-for=\"option in replyOptions\"\n\t\t\t\t\t:key=\"option.key\"\n\t\t\t\t\tv-model=\"replyValues[option.key]\"\n\t\t\t\t\t:data-testid=\"`cn-conversation-option-${option.key}`\">\n\t\t\t\t\t{{ tr(option.label) }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<span v-if=\"draftUrl && draftStatus\"\n\t\t\t\t\tclass=\"cn-conversation-widget__draft-status\"\n\t\t\t\t\trole=\"status\"\n\t\t\t\t\tdata-testid=\"cn-conversation-draft-status\">\n\t\t\t\t\t{{ draftStatus }}\n\t\t\t\t</span>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"draftUrl\"\n\t\t\t\t\tdata-testid=\"cn-conversation-save-draft\"\n\t\t\t\t\t:disabled=\"savingDraft\"\n\t\t\t\t\t@click=\"saveDraft(draft)\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Save as draft') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<template v-if=\"headerAction || statusBadgeText\" #header-actions>\n\t\t\t\t<span v-if=\"statusBadgeText\"\n\t\t\t\t\tclass=\"cn-conversation-widget__badge\"\n\t\t\t\t\tdata-testid=\"cn-conversation-status-badge\">\n\t\t\t\t\t{{ statusBadgeText }}\n\t\t\t\t</span>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"headerAction\"\n\t\t\t\t\tdata-testid=\"cn-conversation-header-action\"\n\t\t\t\t\t@click=\"onHeaderAction\">\n\t\t\t\t\t<template v-if=\"headerAction.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"headerAction.icon\" :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ tr(headerAction.label) }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</CnConversationThread>\n\t\t<p v-if=\"actionError\"\n\t\t\tclass=\"cn-conversation-widget__error\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-conversation-action-error\">\n\t\t\t{{ actionError }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport CnTemplateSelect from '../CnTemplateSelect/CnTemplateSelect.vue'\nimport CnConversationThread from './CnConversationThread.vue'\nimport { dispatchAction } from '../../utils/actionsDispatcher.js'\nimport { formatTimeOfDay } from '../../utils/boardDate.js'\nimport { fetchReferenceObjects } from '../../utils/boardReferenceColumns.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { hasUnresolvedDeepTokens, resolveDeepTokens } from '../../utils/resolveFilterTokens.js'\nimport { userDisplayName } from '../../utils/userDisplayName.js'\n\n/**\n * CnConversationWidget: the `conversation` detail widget type.\n *\n * Renders CnConversationThread from the messages of a record, oldest first.\n * The messages are a list on the bound record (`field`), or the objects of a\n * register list (`source: { register, schema, filter?, limit? }`, the filter\n * token-resolved like a record-list's: `{ \"case\": \"@objectId\" }`).\n *\n * Mapping keys name where each message keeps its parts: `textField` (alias\n * `bodyField`), `timeField` (alias `timestampField`), `authorField` (alias\n * `senderField`), `sideField` (alias `directionField`) with `usValue` (alias\n * `outValue`) for the messages the organisation sent, and `channelField` with\n * an optional `channelMap` from stored value to label (\"email\" to \"E-mail\").\n *\n * The reply box posts to `endpoint` (`@objectId` filled in), or runs\n * `replyAction`, an action descriptor the app decides the meaning of: it is\n * dispatched with `args: [{ text, objectId }]` and `props.text`. After a send\n * the source is read again.\n *\n * `fields: [{ field, side }]` merges several lists of the record by time,\n * each on its side (a ticket's `portalReplies` and `portalAnswers`).\n * `templates` (`{ url, params?, inputLabel, textField? }`) puts a\n * CnTemplateSelect above the reply box; picking one fills the box with the\n * option's `values[textField]` (default `text`). `replyOptions`\n * (`[{ key, label, default? }]`) are checkboxes sent with the reply: in the\n * endpoint's body and as `options` in a `replyAction`'s argument.\n * `statusField` with `statusMap` shows each message's status, and\n * `messageActions` (`[{ id, label, endpoint, method?, when?, errorText? }]`)\n * are buttons on the messages that match `when` (`{ field, in }`,\n * `{ field, equals }`, `{ field, empty: true }`, or a list of them that must\n * all hold); `{field}` in the endpoint is read from the message. `errors`\n * (`{ path, map, default, ok? }`) names an answer's refusal by its status.\n *\n * `channelChips: true` draws a chip per channel above the thread (every\n * `channelMap` label, in map order, then any other channel a message uses).\n * `headerAction` is a button beside the title (`{ label, icon?, ...action }`,\n * DqZaakContact's \"Contact vastleggen\"), dispatched like `replyAction` with\n * `args: [{ objectId }]`; after it the source is read again.\n */\nexport default {\n\tname: 'CnConversationWidget',\n\n\tcomponents: {\n\t\tCnConversationThread,\n\t\tCnIcon,\n\t\tCnTemplateSelect,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t},\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** Pre-bound action dispatcher of the page, for `replyAction`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's content: `field` (the dot-path to the messages on the\n\t\t * record) or `source`, the mapping keys, `endpoint` or `replyAction`,\n\t\t * and the texts (`title`, `replyLabel`, `placeholder`, `sendLabel`,\n\t\t * `usLabel`, `emptyText`, translated).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The bound record. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The bound record's id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Replies sent from this widget that the record does not hold yet. */\n\t\t\tsentHere: [],\n\t\t\t/** The messages read from `source`. */\n\t\t\tlisted: [],\n\t\t\t/** Whether `source` is being read. */\n\t\t\tloading: false,\n\t\t\t/** The reply options' values, by key. */\n\t\t\treplyValues: this.initialReplyValues(),\n\t\t\t/** Why the last message action failed. */\n\t\t\tactionError: '',\n\t\t\t/** The action running, as `<action>|<message>`. */\n\t\t\tacting: '',\n\t\t\t/** The threads `statusBadge` reads. */\n\t\t\tbadgeRows: [],\n\t\t\t/** What the last draft save said: when it was saved, or that it failed. */\n\t\t\tdraftStatus: '',\n\t\t\t/** Whether a draft is being saved. */\n\t\t\tsavingDraft: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object|null} The register list the messages come from, or null. */\n\t\tsource() {\n\t\t\tconst source = this.content?.source\n\t\t\treturn source && typeof source === 'object' && source.register && source.schema ? source : null\n\t\t},\n\n\t\t/** @return {object|null} The header action, or null without a label. */\n\t\t/** @return {string} The latest thread's status (`statusBadge`), mapped and translated; '' for none. */\n\t\tstatusBadgeText() {\n\t\t\tconst badge = this.content?.statusBadge\n\t\t\tif (!badge || this.badgeRows.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst sortField = badge.sortField || ''\n\t\t\tconst time = (row) => {\n\t\t\t\tconst value = sortField ? Date.parse(readPath(row, sortField)) : NaN\n\t\t\t\treturn Number.isNaN(value) ? 0 : value\n\t\t\t}\n\t\t\tconst latest = [...this.badgeRows].sort((a, b) => time(b) - time(a))[0]\n\t\t\tconst raw = readPath(latest, badge.path || 'status')\n\t\t\tif (raw === undefined || raw === null || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst map = badge.map && typeof badge.map === 'object' ? badge.map : {}\n\t\t\treturn this.tr(Object.hasOwn(map, String(raw)) ? map[String(raw)] : String(raw))\n\t\t},\n\n\t\theaderAction() {\n\t\t\tconst action = this.content?.headerAction\n\t\t\treturn action && typeof action === 'object' && typeof action.label === 'string' && action.label !== '' ? action : null\n\t\t},\n\n\t\t/** @return {Array<string>} The `channelMap` labels, translated, each once. */\n\t\tchannelLabels() {\n\t\t\tconst map = this.content?.channelMap && typeof this.content.channelMap === 'object' ? this.content.channelMap : {}\n\t\t\treturn [...new Set(Object.values(map).filter((label) => typeof label === 'string' && label !== '').map((label) => this.tr(label)))]\n\t\t},\n\n\t\t/**\n\t\t * `content.replyOption` with its label translated, or null.\n\t\t *\n\t\t * @return {{label: string, key: string, value?: boolean}|null}\n\t\t * @spec openspec/changes/conversation-reply-option/specs/conversation-source/spec.md#requirement-a-reply-can-carry-a-hint-and-an-option\n\t\t */\n\t\treplyOption() {\n\t\t\tconst option = this.content?.replyOption\n\t\t\treturn option && typeof option === 'object' && option.label && option.key\n\t\t\t\t? { ...option, label: this.tr(option.label) }\n\t\t\t\t: null\n\t\t},\n\n\t\t/** @return {object|null} The template picker config, or null. */\n\t\ttemplates() {\n\t\t\tconst templates = this.content?.templates\n\t\t\treturn templates && typeof templates === 'object' && typeof templates.url === 'string' && templates.url !== '' ? templates : null\n\t\t},\n\n\t\t/** @return {object} The template list's params with tokens resolved. */\n\t\ttemplateParams() {\n\t\t\treturn resolveDeepTokens(this.templates?.params || {}, this.tokenCtx)\n\t\t},\n\n\t\t/** @return {Array<object>} The reply options with a key and a label. */\n\t\treplyOptions() {\n\t\t\tconst list = Array.isArray(this.content?.replyOptions) ? this.content.replyOptions : []\n\t\t\treturn list.filter((option) => option && typeof option.key === 'string' && option.key !== '' && typeof option.label === 'string')\n\t\t},\n\n\t\t/** @return {Array<object>} The message actions with an id, a label and an endpoint. */\n\t\tmessageActions() {\n\t\t\tconst list = Array.isArray(this.content?.messageActions) ? this.content.messageActions : []\n\t\t\treturn list.filter((action) => action && action.id && action.label && typeof action.endpoint === 'string')\n\t\t},\n\n\t\t/** @return {object|null} The reply action, or null. */\n\t\treplyAction() {\n\t\t\tconst action = this.content?.replyAction\n\t\t\treturn action && typeof action === 'object' ? action : null\n\t\t},\n\n\t\t/**\n\t\t * The messages in the thread's shape, oldest first, plus the replies\n\t\t * sent here.\n\t\t *\n\t\t * @return {Array<object>} The messages.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t * @spec openspec/changes/conversation-source/specs/conversation-source/spec.md#requirement-a-conversation-reads-its-messages-from-a-list-and-maps-their-parts\n\t\t */\n\t\tmessages() {\n\t\t\tconst c = this.content || {}\n\t\t\tconst usValue = String(c.outValue ?? c.usValue ?? 'us')\n\t\t\tconst channelMap = c.channelMap && typeof c.channelMap === 'object' ? c.channelMap : {}\n\t\t\tconst statusMap = c.statusMap && typeof c.statusMap === 'object' ? c.statusMap : {}\n\t\t\tconst stored = this.rawMessages()\n\t\t\t\t.map(({ message, side, key }, index) => {\n\t\t\t\t\tconst channel = c.channelField ? readPath(message, c.channelField) : undefined\n\t\t\t\t\tconst channelKey = channel === undefined || channel === null ? '' : String(channel)\n\t\t\t\t\tconst status = c.statusField ? readPath(message, c.statusField) : undefined\n\t\t\t\t\tconst statusKey = status === undefined || status === null ? '' : String(status)\n\t\t\t\t\tconst sideOf = side || (String(readPath(message, c.directionField || c.sideField || 'side')) === usValue ? 'us' : 'them')\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: key,\n\t\t\t\t\t\tauthor: this.authorOf(message, sideOf),\n\t\t\t\t\t\tnote: c.noteField ? this.textOf(readPath(message, c.noteField)) : '',\n\t\t\t\t\t\ttime: readPath(message, c.timestampField || c.timeField || 'time'),\n\t\t\t\t\t\ttext: readPath(message, c.bodyField || c.textField || 'text'),\n\t\t\t\t\t\tside: sideOf,\n\t\t\t\t\t\tchannel: channelKey === '' ? '' : this.tr(Object.hasOwn(channelMap, channelKey) ? channelMap[channelKey] : channelKey),\n\t\t\t\t\t\tstatus: statusKey === '' ? '' : this.tr(Object.hasOwn(statusMap, statusKey) ? statusMap[statusKey] : statusKey),\n\t\t\t\t\t\tactions: this.messageActions\n\t\t\t\t\t\t\t.filter((action) => this.actionApplies(action, message))\n\t\t\t\t\t\t\t.map((action) => ({ id: action.id, label: this.tr(action.label), disabled: this.acting === `${action.id}|${key}` })),\n\t\t\t\t\t\torder: index,\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\tconst at = (message) => {\n\t\t\t\tconst ms = Date.parse(message.time)\n\t\t\t\treturn Number.isNaN(ms) ? null : ms\n\t\t\t}\n\t\t\tstored.sort((a, b) => {\n\t\t\t\tconst ta = at(a)\n\t\t\t\tconst tb = at(b)\n\t\t\t\treturn (ta === null || tb === null || ta === tb) ? a.order - b.order : ta - tb\n\t\t\t})\n\t\t\treturn [...stored, ...this.sentHere]\n\t\t},\n\n\t\t/**\n\t\t * The endpoint with the record's id filled in.\n\t\t *\n\t\t * @return {string} The URL, or '' when the content names none.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\t/**\n\t\t * The reply draft's url (`content.draft.url`, `@objectId` filled in),\n\t\t * or '' without one.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/conversation-reply-draft/specs/conversation-reply-draft/spec.md#requirement-a-reply-can-be-saved-as-a-draft-and-comes-back\n\t\t */\n\t\tdraftUrl() {\n\t\t\tconst url = this.content.draft && this.content.draft.url\n\t\t\tif (typeof url !== 'string' || url === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn url.replace(/@objectId/g, encodeURIComponent(String(this.objectId ?? '')))\n\t\t},\n\n\t\tendpoint() {\n\t\t\tconst url = this.content.endpoint\n\t\t\tif (typeof url !== 'string' || url === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn url.replace(/@objectId/g, encodeURIComponent(String(this.objectId ?? '')))\n\t\t},\n\n\t\t/** @return {object} The token context for `source.filter` and `replyAction`. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.objectId, object: this.objectData || {} }\n\t\t},\n\t},\n\n\twatch: {\n\t\t// The record was read again, so it now holds what was sent from here.\n\t\tobjectData() {\n\t\t\tthis.sentHere = []\n\t\t},\n\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.loadSource()\n\t\t\t\tthis.loadBadge()\n\t\t\t\tthis.loadDraft()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tsubscribe('cn:page:refresh', this.onPageRefresh)\n\t\tsubscribe('cn:conversation:reply-sent', this.onReplySentElsewhere)\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.onPageRefresh)\n\t\tunsubscribe('cn:conversation:reply-sent', this.onReplySentElsewhere)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Read the saved reply draft into the reply box.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-reply-draft/specs/conversation-reply-draft/spec.md#requirement-a-reply-can-be-saved-as-a-draft-and-comes-back\n\t\t */\n\t\tasync loadDraft() {\n\t\t\tif (!this.draftUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { generateUrl } = await import('@nextcloud/router')\n\t\t\t\tconst { data } = await axios.get(generateUrl(this.draftUrl))\n\t\t\t\tconst text = data && typeof data.text === 'string' ? data.text : ''\n\t\t\t\tif (text !== '' && this.$refs.thread) {\n\t\t\t\t\tthis.$refs.thread.setDraft(text)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// No saved draft to read leaves the box empty.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Store the reply box as the draft and say when it was saved.\n\t\t *\n\t\t * @param {string} text The reply box's text.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync saveDraft(text) {\n\t\t\tthis.savingDraft = true\n\t\t\ttry {\n\t\t\t\tawait this.storeDraft(String(text ?? ''))\n\t\t\t\tthis.draftStatus = t('nextcloud-vue', 'Draft saved at {time}', { time: formatTimeOfDay(new Date()) })\n\t\t\t} catch {\n\t\t\t\tthis.draftStatus = t('nextcloud-vue', 'The draft could not be saved')\n\t\t\t} finally {\n\t\t\t\tthis.savingDraft = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A reply on this record went out through a dialog or another surface\n\t\t * (`cn:conversation:reply-sent` with `{ objectId }`): the saved draft\n\t\t * and the reply box are cleared.\n\t\t *\n\t\t * @param {{objectId?: string}} payload The record the reply was on.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-reply-draft/specs/conversation-reply-draft/spec.md#requirement-a-reply-can-be-saved-as-a-draft-and-comes-back\n\t\t */\n\t\tasync onReplySentElsewhere(payload) {\n\t\t\tif (!this.draftUrl || String(payload?.objectId ?? '') !== String(this.objectId ?? '')) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.$refs.thread) {\n\t\t\t\tthis.$refs.thread.setDraft('')\n\t\t\t}\n\t\t\tthis.draftStatus = ''\n\t\t\ttry {\n\t\t\t\tawait this.storeDraft('')\n\t\t\t} catch {\n\t\t\t\t// The next save overwrites a draft that could not be cleared.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * PUT the draft text.\n\t\t *\n\t\t * @param {string} text The text; '' clears the draft.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync storeDraft(text) {\n\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\tconst { generateUrl } = await import('@nextcloud/router')\n\t\t\tawait axios.put(generateUrl(this.draftUrl), { text })\n\t\t},\n\n\t\t/**\n\t\t * Read the messages again when the page refreshes (a dialog sent one).\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onPageRefresh() {\n\t\t\tawait Promise.all([this.loadSource(), this.loadBadge()])\n\t\t},\n\n\t\t/**\n\t\t * Read the threads whose latest status `statusBadge` shows\n\t\t * (`{ source: { register, schema, filter?, limit? }, sortField?, path?, map? }`).\n\t\t * A filter whose token does not resolve, or a failed read, shows no badge.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-reply-tools/specs/conversation/spec.md#requirement-a-conversation-shows-the-latest-thread-status-and-a-status-can-open-a-follow-up\n\t\t */\n\t\tasync loadBadge() {\n\t\t\tconst source = this.content?.statusBadge?.source\n\t\t\tif (!source || !source.register || !source.schema) {\n\t\t\t\tthis.badgeRows = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst filter = resolveDeepTokens(source.filter || {}, this.tokenCtx)\n\t\t\tif (hasUnresolvedDeepTokens(filter) || Object.values(filter).some((value) => value === '' || value === null || value === undefined)) {\n\t\t\t\tthis.badgeRows = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst rows = await fetchReferenceObjects({ register: source.register, schema: source.schema, filter, limit: source.limit || 50 })\n\t\t\t\tthis.badgeRows = Array.isArray(rows) ? rows : []\n\t\t\t} catch {\n\t\t\t\tthis.badgeRows = []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The stored messages with the side their list gives them: one list\n\t\t * (`field` or `source`), or several merged (`fields`).\n\t\t *\n\t\t * @return {Array<{message: object, side: string, key: string}>} The messages.\n\t\t * @spec openspec/changes/conversation-reply-tools/specs/conversation/spec.md#requirement-a-conversation-merges-several-lists-of-the-record\n\t\t */\n\t\trawMessages() {\n\t\t\tconst c = this.content || {}\n\t\t\tconst lists = !this.source && Array.isArray(c.fields) && c.fields.length > 0\n\t\t\t\t? c.fields.filter((entry) => entry && typeof entry.field === 'string').map((entry) => ({ list: readPath(this.objectData || {}, entry.field), side: entry.side === 'us' ? 'us' : 'them', prefix: entry.field }))\n\t\t\t\t: [{ list: this.source ? this.listed : readPath(this.objectData || {}, c.field || 'messages'), side: '', prefix: 'message' }]\n\t\t\treturn lists.flatMap(({ list, side, prefix }) => (Array.isArray(list) ? list : [])\n\t\t\t\t.filter((message) => message && typeof message === 'object')\n\t\t\t\t.map((message, index) => ({ message, side, key: String(message.id ?? `${prefix}-${index}`) })))\n\t\t},\n\n\t\t/**\n\t\t * Whether a message action applies to a message (`when`).\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} message The stored message.\n\t\t * @return {boolean}\n\t\t */\n\t\tactionApplies(action, message) {\n\t\t\tconst conditions = [].concat(action.when || [])\n\t\t\treturn conditions.every((when) => {\n\t\t\t\tif (!when || typeof when !== 'object' || typeof when.field !== 'string') {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\tconst value = readPath(message, when.field)\n\t\t\t\tif (when.empty === true) {\n\t\t\t\t\treturn value === undefined || value === null || value === ''\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(when.in)) {\n\t\t\t\t\treturn when.in.map(String).includes(String(value))\n\t\t\t\t}\n\t\t\t\treturn String(value) === String(when.equals)\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The reply options at their defaults.\n\t\t *\n\t\t * @return {object} Values by key.\n\t\t */\n\t\tinitialReplyValues() {\n\t\t\tconst list = Array.isArray(this.content?.replyOptions) ? this.content.replyOptions : []\n\t\t\treturn Object.fromEntries(list.filter((option) => option && option.key).map((option) => [option.key, option.default === true]))\n\t\t},\n\n\t\t/**\n\t\t * Put a picked template's text in the reply box.\n\t\t *\n\t\t * @param {object|null} option The template option.\n\t\t * @param {(text: string) => void} setDraft The thread's draft setter.\n\t\t * @return {void}\n\t\t */\n\t\tapplyTemplate(option, setDraft) {\n\t\t\tif (!option || !option.values) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst text = option.values[this.templates.textField || 'text']\n\t\t\tif (typeof text === 'string') {\n\t\t\t\tsetDraft(text)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run a message action: call its endpoint with the message's fields,\n\t\t * then read the messages again.\n\t\t *\n\t\t * @param {{action: string, message: string}} event Which action on which message.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-reply-tools/specs/conversation/spec.md#requirement-a-message-carries-its-status-and-actions\n\t\t */\n\t\tasync onMessageAction({ action: actionId, message: key }) {\n\t\t\tconst action = this.messageActions.find((entry) => entry.id === actionId)\n\t\t\tconst stored = this.rawMessages().find((entry) => entry.key === key)\n\t\t\tif (!action || !stored || this.acting) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.actionError = ''\n\t\t\tthis.acting = `${actionId}|${key}`\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([import('@nextcloud/axios'), import('@nextcloud/router')])\n\t\t\t\tconst path = action.endpoint\n\t\t\t\t\t.replace(/@objectId/g, encodeURIComponent(String(this.objectId ?? '')))\n\t\t\t\t\t.replace(/\\{([\\w.]+)\\}/g, (_m, field) => encodeURIComponent(String(readPath(stored.message, field) ?? '')))\n\t\t\t\tconst response = await axios.request({ method: String(action.method || 'POST').toLowerCase(), url: generateUrl(path) })\n\t\t\t\tif (await this.followUp(action, response?.data)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst refusal = this.actionRefusal(action, response?.data)\n\t\t\t\tif (refusal) {\n\t\t\t\t\tthis.actionError = refusal\n\t\t\t\t}\n\t\t\t\tawait this.loadSource()\n\t\t\t} catch (error) {\n\t\t\t\tif (await this.followUp(action, error?.response?.data)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.actionError = this.actionRefusal(action, error?.response?.data) || this.tr(action.errorText || 'The action failed.')\n\t\t\t} finally {\n\t\t\t\tthis.acting = ''\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run the follow-up action a message action's answer asks for: the\n\t\t * status at `errors.path` (default `status`) looked up in `onStatus`,\n\t\t * dispatched like `headerAction`, tokens resolved against the record.\n\t\t *\n\t\t * @param {object} action The message action.\n\t\t * @param {object|undefined} answer The response body.\n\t\t * @return {Promise<boolean>} True when a follow-up ran.\n\t\t * @spec openspec/changes/conversation-reply-tools/specs/conversation/spec.md#requirement-a-conversation-shows-the-latest-thread-status-and-a-status-can-open-a-follow-up\n\t\t */\n\t\tasync followUp(action, answer) {\n\t\t\tconst map = action.onStatus\n\t\t\tif (!map || typeof map !== 'object' || !answer || typeof answer !== 'object') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst status = readPath(answer, action.errors?.path || 'status')\n\t\t\tconst next = status === undefined || status === null ? null : map[String(status)]\n\t\t\tif (!next || typeof next !== 'object') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst resolved = resolveDeepTokens(next, this.tokenCtx)\n\t\t\ttry {\n\t\t\t\tawait (typeof this.cnDispatchAction === 'function'\n\t\t\t\t\t? this.cnDispatchAction(resolved)\n\t\t\t\t\t: dispatchAction(resolved, { router: this.$router || null }))\n\t\t\t} catch {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t},\n\n\t\t/**\n\t\t * The text a message action's answer names, by `errors` (`{ path, map,\n\t\t * ok? }`): the status at `path` mapped to a text. A status listed in `ok`\n\t\t * (default `[\"sent\", \"ok\"]`) is no refusal.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object|undefined} answer The response body.\n\t\t * @return {string} The text, '' for none.\n\t\t */\n\t\tactionRefusal(action, answer) {\n\t\t\tconst errors = action.errors\n\t\t\tif (!errors || typeof errors !== 'object' || !answer || typeof answer !== 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst status = readPath(answer, errors.path || 'status')\n\t\t\tif (status === undefined || status === null || (errors.ok || ['sent', 'ok']).map(String).includes(String(status))) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst text = (errors.map || {})[String(status)] || errors.default\n\t\t\treturn text ? this.tr(text) : ''\n\t\t},\n\n\t\t/**\n\t\t * Who wrote a message: `usAuthorField` / `themAuthorField` for its\n\t\t * side, else `senderField` (`authorField`). A field written\n\t\t * `@object.<path>` reads the bound record (the case's requester on an\n\t\t * incoming message). With `usAuthorFormat` / `themAuthorFormat` set to\n\t\t * `user` the value is a user id, shown by its display name.\n\t\t *\n\t\t * @param {object} message The message.\n\t\t * @param {string} side `us` or `them`.\n\t\t * @return {string} The author, or '' when the message names none.\n\t\t * @spec openspec/changes/conversation-board-bubble/specs/conversation-source/spec.md#requirement-a-message-names-its-author-per-side-its-direction-and-a-note\n\t\t */\n\t\tauthorOf(message, side) {\n\t\t\tconst c = this.content || {}\n\t\t\tconst field = (side === 'us' ? c.usAuthorField : c.themAuthorField) || c.senderField || c.authorField || 'author'\n\t\t\tconst value = typeof field === 'string' && field.startsWith('@object.')\n\t\t\t\t? readPath(this.objectData || {}, field.slice('@object.'.length))\n\t\t\t\t: readPath(message, field)\n\t\t\tconst text = this.textOf(value)\n\t\t\tconst format = side === 'us' ? c.usAuthorFormat : c.themAuthorFormat\n\t\t\treturn format === 'user' && text !== '' ? (userDisplayName(text) || text) : text\n\t\t},\n\n\t\t/**\n\t\t * @param {unknown} value A stored value.\n\t\t * @return {string} It as text, or '' for none.\n\t\t */\n\t\ttextOf(value) {\n\t\t\treturn value === undefined || value === null || typeof value === 'object' ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * Translate through the app's translate.\n\t\t *\n\t\t * @param {string} key The source string.\n\t\t * @return {string}\n\t\t */\n\t\ttr(key) {\n\t\t\treturn key && typeof this.cnTranslate === 'function' ? this.cnTranslate(key) : (key || '')\n\t\t},\n\n\t\t/**\n\t\t * Read the messages from `source`. A filter whose token does not\n\t\t * resolve sends no request; a failed read leaves the thread empty.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-source/specs/conversation-source/spec.md#requirement-a-conversation-reads-its-messages-from-a-list-and-maps-their-parts\n\t\t */\n\t\tasync loadSource() {\n\t\t\tif (!this.source) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst raw = this.source.filter || {}\n\t\t\tconst filter = resolveDeepTokens(raw, this.tokenCtx)\n\t\t\tconst emptied = Object.keys(raw).some((key) => typeof raw[key] === 'string' && raw[key].startsWith('@') && (filter[key] === '' || filter[key] === null || filter[key] === undefined))\n\t\t\tif (emptied || hasUnresolvedDeepTokens(filter)) {\n\t\t\t\tthis.listed = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tthis.listed = await fetchReferenceObjects({ register: this.source.register, schema: this.source.schema, filter, limit: this.source.limit || 200 })\n\t\t\t\tthis.sentHere = []\n\t\t\t} catch {\n\t\t\t\tthis.listed = []\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 * Run `replyAction` with the reply, when there is one; the endpoint\n\t\t * path is the thread's own.\n\t\t *\n\t\t * @param {string} text The reply.\n\t\t * @param {object} [extras] The reply option's state, `{ [key]: boolean }`.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-source/specs/conversation-source/spec.md#requirement-a-reply-can-run-an-app-action\n\t\t * @spec openspec/changes/conversation-reply-option/specs/conversation-source/spec.md#requirement-a-reply-can-carry-a-hint-and-an-option\n\t\t */\n\t\tasync onSend(text, extras = {}) {\n\t\t\tif (!this.replyAction) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst resolved = resolveDeepTokens(this.replyAction, this.tokenCtx)\n\t\t\tconst options = this.replyOptions.length > 0 ? { options: { ...this.replyValues } } : {}\n\t\t\tconst action = { ...resolved, args: [{ text, objectId: this.objectId, ...extras, ...options }], props: { ...(resolved.props || {}), text, ...extras, ...options } }\n\t\t\tconst result = typeof this.cnDispatchAction === 'function'\n\t\t\t\t? this.cnDispatchAction(action)\n\t\t\t\t: dispatchAction(action, { router: this.$router || null })\n\t\t\ttry {\n\t\t\t\tconst outcome = await result\n\t\t\t\tif (outcome === false) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.source) {\n\t\t\t\tawait this.loadSource()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.onSent({ text })\n\t\t},\n\n\t\t/**\n\t\t * Run `headerAction` with the record id, then read the source again.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onHeaderAction() {\n\t\t\tif (!this.headerAction) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst { label, icon, ...rest } = resolveDeepTokens(this.headerAction, this.tokenCtx)\n\t\t\tconst action = { ...rest, args: [{ objectId: this.objectId }] }\n\t\t\ttry {\n\t\t\t\tconst outcome = await (typeof this.cnDispatchAction === 'function'\n\t\t\t\t\t? this.cnDispatchAction(action)\n\t\t\t\t\t: dispatchAction(action, { router: this.$router || null }))\n\t\t\t\tif (outcome === false) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadSource()\n\t\t},\n\n\t\t/**\n\t\t * Show an accepted reply at once, without waiting for the record.\n\t\t *\n\t\t * @param {object} data The endpoint's response.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tonSent(data) {\n\t\t\tconst text = data?.message ?? data?.text\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.draftUrl) {\n\t\t\t\tthis.storeDraft('')\n\t\t\t}\n\t\t\tthis.sentHere.push({\n\t\t\t\tid: `sent-${this.sentHere.length}`,\n\t\t\t\ttime: new Date().toISOString(),\n\t\t\t\ttext,\n\t\t\t\tside: 'us',\n\t\t\t})\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-conversation-widget__badge {\n\tpadding: 2px 10px;\n\tborder-radius: var(--border-radius-pill);\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-conversation-widget__error {\n\tcolor: var(--color-error-text, var(--color-error));\n\tmargin: calc(2 * var(--default-grid-baseline)) 0 0;\n}\n\n.cn-case-widget-card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: calc(5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-widget__draft-status {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n</style>\n"],"names":["CnConversationThread","CnIcon","CnTemplateSelect","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnConversationWidget.vue2.js","sources":["../../../../src/components/CnConversationThread/CnConversationWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-case-widget-card\">\n\t\t<CnConversationThread\n\t\t\tref=\"thread\"\n\t\t\t:messages=\"messages\"\n\t\t\t:title=\"tr(content.title || '')\"\n\t\t\t:subtitle=\"tr(content.subtitle || '')\"\n\t\t\t:showDirection=\"content.showDirection === true\"\n\t\t\t:allowReply=\"content.allowReply !== false\"\n\t\t\t:replyLabel=\"content.replyLabel ? tr(content.replyLabel) : undefined\"\n\t\t\t:placeholder=\"tr(content.placeholder || '')\"\n\t\t\t:sendLabel=\"content.sendLabel ? tr(content.sendLabel) : undefined\"\n\t\t\t:replyHint=\"tr(content.replyHint || '')\"\n\t\t\t:replyOption=\"replyOption\"\n\t\t\t:usLabel=\"content.usLabel ? tr(content.usLabel) : undefined\"\n\t\t\t:endpoint=\"replyAction ? '' : endpoint\"\n\t\t\t:loading=\"loading\"\n\t\t\t:emptyText=\"content.emptyText ? tr(content.emptyText) : undefined\"\n\t\t\t:channelFilter=\"content.channelChips === true\"\n\t\t\t:channels=\"channelLabels\"\n\t\t\t:payload=\"replyValues\"\n\t\t\t@send=\"onSend\"\n\t\t\t@sent=\"onSent\"\n\t\t\t@messageAction=\"onMessageAction\">\n\t\t\t<template v-if=\"templates\" #reply-tools=\"{ setDraft }\">\n\t\t\t\t<CnTemplateSelect\n\t\t\t\t\t:url=\"templates.url\"\n\t\t\t\t\t:params=\"templateParams\"\n\t\t\t\t\t:inputLabel=\"tr(templates.inputLabel || 'Template')\"\n\t\t\t\t\tdata-testid=\"cn-conversation-templates\"\n\t\t\t\t\t@apply=\"applyTemplate($event, setDraft)\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"replyOptions.length > 0 || draftUrl\" #reply-actions=\"{ draft }\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\tv-for=\"option in replyOptions\"\n\t\t\t\t\t:key=\"option.key\"\n\t\t\t\t\tv-model=\"replyValues[option.key]\"\n\t\t\t\t\t:data-testid=\"`cn-conversation-option-${option.key}`\">\n\t\t\t\t\t{{ tr(option.label) }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<span v-if=\"draftUrl && draftStatus\"\n\t\t\t\t\tclass=\"cn-conversation-widget__draft-status\"\n\t\t\t\t\trole=\"status\"\n\t\t\t\t\tdata-testid=\"cn-conversation-draft-status\">\n\t\t\t\t\t{{ draftStatus }}\n\t\t\t\t</span>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"draftUrl\"\n\t\t\t\t\tdata-testid=\"cn-conversation-save-draft\"\n\t\t\t\t\t:disabled=\"savingDraft\"\n\t\t\t\t\t@click=\"saveDraft(draft)\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Save as draft') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<template v-if=\"headerAction || statusBadgeText\" #header-actions>\n\t\t\t\t<span v-if=\"statusBadgeText\"\n\t\t\t\t\tclass=\"cn-conversation-widget__badge\"\n\t\t\t\t\tdata-testid=\"cn-conversation-status-badge\">\n\t\t\t\t\t{{ statusBadgeText }}\n\t\t\t\t</span>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"headerAction\"\n\t\t\t\t\tdata-testid=\"cn-conversation-header-action\"\n\t\t\t\t\t@click=\"onHeaderAction\">\n\t\t\t\t\t<template v-if=\"headerAction.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"headerAction.icon\" :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ tr(headerAction.label) }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</CnConversationThread>\n\t\t<p v-if=\"actionError\"\n\t\t\tclass=\"cn-conversation-widget__error\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-conversation-action-error\">\n\t\t\t{{ actionError }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport CnTemplateSelect from '../CnTemplateSelect/CnTemplateSelect.vue'\nimport CnConversationThread from './CnConversationThread.vue'\nimport { dispatchAction } from '../../utils/actionsDispatcher.js'\nimport { formatTimeOfDay } from '../../utils/boardDate.js'\nimport { fetchReferenceObjects } from '../../utils/boardReferenceColumns.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { hasUnresolvedDeepTokens, resolveDeepTokens } from '../../utils/resolveFilterTokens.js'\nimport { userDisplayName } from '../../utils/userDisplayName.js'\n\n/**\n * CnConversationWidget: the `conversation` detail widget type.\n *\n * Renders CnConversationThread from the messages of a record, oldest first.\n * The messages are a list on the bound record (`field`), or the objects of a\n * register list (`source: { register, schema, filter?, limit? }`, the filter\n * token-resolved like a record-list's: `{ \"case\": \"@objectId\" }`).\n *\n * Mapping keys name where each message keeps its parts: `textField` (alias\n * `bodyField`), `timeField` (alias `timestampField`), `authorField` (alias\n * `senderField`), `sideField` (alias `directionField`) with `usValue` (alias\n * `outValue`) for the messages the organisation sent, and `channelField` with\n * an optional `channelMap` from stored value to label (\"email\" to \"E-mail\")\n * and `channelIcons` from stored value to an icon name, drawn before the label.\n *\n * The reply box posts to `endpoint` (`@objectId` filled in), or runs\n * `replyAction`, an action descriptor the app decides the meaning of: it is\n * dispatched with `args: [{ text, objectId }]` and `props.text`. After a send\n * the source is read again.\n *\n * `fields: [{ field, side }]` merges several lists of the record by time,\n * each on its side (a ticket's `portalReplies` and `portalAnswers`).\n * `templates` (`{ url, params?, inputLabel, textField? }`) puts a\n * CnTemplateSelect above the reply box; picking one fills the box with the\n * option's `values[textField]` (default `text`). `replyOptions`\n * (`[{ key, label, default? }]`) are checkboxes sent with the reply: in the\n * endpoint's body and as `options` in a `replyAction`'s argument.\n * `statusField` with `statusMap` shows each message's status, and\n * `messageActions` (`[{ id, label, endpoint, method?, when?, errorText? }]`)\n * are buttons on the messages that match `when` (`{ field, in }`,\n * `{ field, equals }`, `{ field, empty: true }`, or a list of them that must\n * all hold); `{field}` in the endpoint is read from the message. `errors`\n * (`{ path, map, default, ok? }`) names an answer's refusal by its status.\n *\n * `channelChips: true` draws a chip per channel above the thread (every\n * `channelMap` label, in map order, then any other channel a message uses).\n * `headerAction` is a button beside the title (`{ label, icon?, ...action }`,\n * DqZaakContact's \"Contact vastleggen\"), dispatched like `replyAction` with\n * `args: [{ objectId }]`; after it the source is read again.\n */\nexport default {\n\tname: 'CnConversationWidget',\n\n\tcomponents: {\n\t\tCnConversationThread,\n\t\tCnIcon,\n\t\tCnTemplateSelect,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t},\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** Pre-bound action dispatcher of the page, for `replyAction`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's content: `field` (the dot-path to the messages on the\n\t\t * record) or `source`, the mapping keys, `endpoint` or `replyAction`,\n\t\t * and the texts (`title`, `replyLabel`, `placeholder`, `sendLabel`,\n\t\t * `usLabel`, `emptyText`, translated).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The bound record. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The bound record's id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\t/** Replies sent from this widget that the record does not hold yet. */\n\t\t\tsentHere: [],\n\t\t\t/** The messages read from `source`. */\n\t\t\tlisted: [],\n\t\t\t/** Whether `source` is being read. */\n\t\t\tloading: false,\n\t\t\t/** The reply options' values, by key. */\n\t\t\treplyValues: this.initialReplyValues(),\n\t\t\t/** Why the last message action failed. */\n\t\t\tactionError: '',\n\t\t\t/** The action running, as `<action>|<message>`. */\n\t\t\tacting: '',\n\t\t\t/** The threads `statusBadge` reads. */\n\t\t\tbadgeRows: [],\n\t\t\t/** What the last draft save said: when it was saved, or that it failed. */\n\t\t\tdraftStatus: '',\n\t\t\t/** Whether a draft is being saved. */\n\t\t\tsavingDraft: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object|null} The register list the messages come from, or null. */\n\t\tsource() {\n\t\t\tconst source = this.content?.source\n\t\t\treturn source && typeof source === 'object' && source.register && source.schema ? source : null\n\t\t},\n\n\t\t/** @return {object|null} The header action, or null without a label. */\n\t\t/** @return {string} The latest thread's status (`statusBadge`), mapped and translated; '' for none. */\n\t\tstatusBadgeText() {\n\t\t\tconst badge = this.content?.statusBadge\n\t\t\tif (!badge || this.badgeRows.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst sortField = badge.sortField || ''\n\t\t\tconst time = (row) => {\n\t\t\t\tconst value = sortField ? Date.parse(readPath(row, sortField)) : NaN\n\t\t\t\treturn Number.isNaN(value) ? 0 : value\n\t\t\t}\n\t\t\tconst latest = [...this.badgeRows].sort((a, b) => time(b) - time(a))[0]\n\t\t\tconst raw = readPath(latest, badge.path || 'status')\n\t\t\tif (raw === undefined || raw === null || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst map = badge.map && typeof badge.map === 'object' ? badge.map : {}\n\t\t\treturn this.tr(Object.hasOwn(map, String(raw)) ? map[String(raw)] : String(raw))\n\t\t},\n\n\t\theaderAction() {\n\t\t\tconst action = this.content?.headerAction\n\t\t\treturn action && typeof action === 'object' && typeof action.label === 'string' && action.label !== '' ? action : null\n\t\t},\n\n\t\t/** @return {Array<string>} The `channelMap` labels, translated, each once. */\n\t\tchannelLabels() {\n\t\t\tconst map = this.content?.channelMap && typeof this.content.channelMap === 'object' ? this.content.channelMap : {}\n\t\t\treturn [...new Set(Object.values(map).filter((label) => typeof label === 'string' && label !== '').map((label) => this.tr(label)))]\n\t\t},\n\n\t\t/**\n\t\t * `content.replyOption` with its label translated, or null.\n\t\t *\n\t\t * @return {{label: string, key: string, value?: boolean}|null}\n\t\t * @spec openspec/changes/conversation-reply-option/specs/conversation-source/spec.md#requirement-a-reply-can-carry-a-hint-and-an-option\n\t\t */\n\t\treplyOption() {\n\t\t\tconst option = this.content?.replyOption\n\t\t\treturn option && typeof option === 'object' && option.label && option.key\n\t\t\t\t? { ...option, label: this.tr(option.label) }\n\t\t\t\t: null\n\t\t},\n\n\t\t/** @return {object|null} The template picker config, or null. */\n\t\ttemplates() {\n\t\t\tconst templates = this.content?.templates\n\t\t\treturn templates && typeof templates === 'object' && typeof templates.url === 'string' && templates.url !== '' ? templates : null\n\t\t},\n\n\t\t/** @return {object} The template list's params with tokens resolved. */\n\t\ttemplateParams() {\n\t\t\treturn resolveDeepTokens(this.templates?.params || {}, this.tokenCtx)\n\t\t},\n\n\t\t/** @return {Array<object>} The reply options with a key and a label. */\n\t\treplyOptions() {\n\t\t\tconst list = Array.isArray(this.content?.replyOptions) ? this.content.replyOptions : []\n\t\t\treturn list.filter((option) => option && typeof option.key === 'string' && option.key !== '' && typeof option.label === 'string')\n\t\t},\n\n\t\t/** @return {Array<object>} The message actions with an id, a label and an endpoint. */\n\t\tmessageActions() {\n\t\t\tconst list = Array.isArray(this.content?.messageActions) ? this.content.messageActions : []\n\t\t\treturn list.filter((action) => action && action.id && action.label && typeof action.endpoint === 'string')\n\t\t},\n\n\t\t/** @return {object|null} The reply action, or null. */\n\t\treplyAction() {\n\t\t\tconst action = this.content?.replyAction\n\t\t\treturn action && typeof action === 'object' ? action : null\n\t\t},\n\n\t\t/**\n\t\t * The messages in the thread's shape, oldest first, plus the replies\n\t\t * sent here.\n\t\t *\n\t\t * @return {Array<object>} The messages.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t * @spec openspec/changes/conversation-source/specs/conversation-source/spec.md#requirement-a-conversation-reads-its-messages-from-a-list-and-maps-their-parts\n\t\t */\n\t\tmessages() {\n\t\t\tconst c = this.content || {}\n\t\t\tconst usValue = String(c.outValue ?? c.usValue ?? 'us')\n\t\t\tconst channelMap = c.channelMap && typeof c.channelMap === 'object' ? c.channelMap : {}\n\t\t\tconst channelIcons = c.channelIcons && typeof c.channelIcons === 'object' ? c.channelIcons : {}\n\t\t\tconst statusMap = c.statusMap && typeof c.statusMap === 'object' ? c.statusMap : {}\n\t\t\tconst stored = this.rawMessages()\n\t\t\t\t.map(({ message, side, key }, index) => {\n\t\t\t\t\tconst channel = c.channelField ? readPath(message, c.channelField) : undefined\n\t\t\t\t\tconst channelKey = channel === undefined || channel === null ? '' : String(channel)\n\t\t\t\t\tconst status = c.statusField ? readPath(message, c.statusField) : undefined\n\t\t\t\t\tconst statusKey = status === undefined || status === null ? '' : String(status)\n\t\t\t\t\tconst sideOf = side || (String(readPath(message, c.directionField || c.sideField || 'side')) === usValue ? 'us' : 'them')\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: key,\n\t\t\t\t\t\tauthor: this.authorOf(message, sideOf),\n\t\t\t\t\t\tnote: c.noteField ? this.textOf(readPath(message, c.noteField)) : '',\n\t\t\t\t\t\ttime: readPath(message, c.timestampField || c.timeField || 'time'),\n\t\t\t\t\t\ttext: readPath(message, c.bodyField || c.textField || 'text'),\n\t\t\t\t\t\tside: sideOf,\n\t\t\t\t\t\tchannel: channelKey === '' ? '' : this.tr(Object.hasOwn(channelMap, channelKey) ? channelMap[channelKey] : channelKey),\n\t\t\t\t\t\t// @spec openspec/changes/conversation-channel-icons/specs/conversation-channel-icons/spec.md#requirement-a-messages-channel-can-carry-its-icon\n\t\t\t\t\t\tchannelIcon: Object.hasOwn(channelIcons, channelKey) && typeof channelIcons[channelKey] === 'string' ? channelIcons[channelKey] : '',\n\t\t\t\t\t\tstatus: statusKey === '' ? '' : this.tr(Object.hasOwn(statusMap, statusKey) ? statusMap[statusKey] : statusKey),\n\t\t\t\t\t\tactions: this.messageActions\n\t\t\t\t\t\t\t.filter((action) => this.actionApplies(action, message))\n\t\t\t\t\t\t\t.map((action) => ({ id: action.id, label: this.tr(action.label), disabled: this.acting === `${action.id}|${key}` })),\n\t\t\t\t\t\torder: index,\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\tconst at = (message) => {\n\t\t\t\tconst ms = Date.parse(message.time)\n\t\t\t\treturn Number.isNaN(ms) ? null : ms\n\t\t\t}\n\t\t\tstored.sort((a, b) => {\n\t\t\t\tconst ta = at(a)\n\t\t\t\tconst tb = at(b)\n\t\t\t\treturn (ta === null || tb === null || ta === tb) ? a.order - b.order : ta - tb\n\t\t\t})\n\t\t\treturn [...stored, ...this.sentHere]\n\t\t},\n\n\t\t/**\n\t\t * The endpoint with the record's id filled in.\n\t\t *\n\t\t * @return {string} The URL, or '' when the content names none.\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\t/**\n\t\t * The reply draft's url (`content.draft.url`, `@objectId` filled in),\n\t\t * or '' without one.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/conversation-reply-draft/specs/conversation-reply-draft/spec.md#requirement-a-reply-can-be-saved-as-a-draft-and-comes-back\n\t\t */\n\t\tdraftUrl() {\n\t\t\tconst url = this.content.draft && this.content.draft.url\n\t\t\tif (typeof url !== 'string' || url === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn url.replace(/@objectId/g, encodeURIComponent(String(this.objectId ?? '')))\n\t\t},\n\n\t\tendpoint() {\n\t\t\tconst url = this.content.endpoint\n\t\t\tif (typeof url !== 'string' || url === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn url.replace(/@objectId/g, encodeURIComponent(String(this.objectId ?? '')))\n\t\t},\n\n\t\t/** @return {object} The token context for `source.filter` and `replyAction`. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.objectId, object: this.objectData || {} }\n\t\t},\n\t},\n\n\twatch: {\n\t\t// The record was read again, so it now holds what was sent from here.\n\t\tobjectData() {\n\t\t\tthis.sentHere = []\n\t\t},\n\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.loadSource()\n\t\t\t\tthis.loadBadge()\n\t\t\t\tthis.loadDraft()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tsubscribe('cn:page:refresh', this.onPageRefresh)\n\t\tsubscribe('cn:conversation:reply-sent', this.onReplySentElsewhere)\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.onPageRefresh)\n\t\tunsubscribe('cn:conversation:reply-sent', this.onReplySentElsewhere)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Read the saved reply draft into the reply box.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-reply-draft/specs/conversation-reply-draft/spec.md#requirement-a-reply-can-be-saved-as-a-draft-and-comes-back\n\t\t */\n\t\tasync loadDraft() {\n\t\t\tif (!this.draftUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { generateUrl } = await import('@nextcloud/router')\n\t\t\t\tconst { data } = await axios.get(generateUrl(this.draftUrl))\n\t\t\t\tconst text = data && typeof data.text === 'string' ? data.text : ''\n\t\t\t\tif (text !== '' && this.$refs.thread) {\n\t\t\t\t\tthis.$refs.thread.setDraft(text)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// No saved draft to read leaves the box empty.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Store the reply box as the draft and say when it was saved.\n\t\t *\n\t\t * @param {string} text The reply box's text.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync saveDraft(text) {\n\t\t\tthis.savingDraft = true\n\t\t\ttry {\n\t\t\t\tawait this.storeDraft(String(text ?? ''))\n\t\t\t\tthis.draftStatus = t('nextcloud-vue', 'Draft saved at {time}', { time: formatTimeOfDay(new Date()) })\n\t\t\t} catch {\n\t\t\t\tthis.draftStatus = t('nextcloud-vue', 'The draft could not be saved')\n\t\t\t} finally {\n\t\t\t\tthis.savingDraft = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A reply on this record went out through a dialog or another surface\n\t\t * (`cn:conversation:reply-sent` with `{ objectId }`): the saved draft\n\t\t * and the reply box are cleared.\n\t\t *\n\t\t * @param {{objectId?: string}} payload The record the reply was on.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-reply-draft/specs/conversation-reply-draft/spec.md#requirement-a-reply-can-be-saved-as-a-draft-and-comes-back\n\t\t */\n\t\tasync onReplySentElsewhere(payload) {\n\t\t\tif (!this.draftUrl || String(payload?.objectId ?? '') !== String(this.objectId ?? '')) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.$refs.thread) {\n\t\t\t\tthis.$refs.thread.setDraft('')\n\t\t\t}\n\t\t\tthis.draftStatus = ''\n\t\t\ttry {\n\t\t\t\tawait this.storeDraft('')\n\t\t\t} catch {\n\t\t\t\t// The next save overwrites a draft that could not be cleared.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * PUT the draft text.\n\t\t *\n\t\t * @param {string} text The text; '' clears the draft.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync storeDraft(text) {\n\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\tconst { generateUrl } = await import('@nextcloud/router')\n\t\t\tawait axios.put(generateUrl(this.draftUrl), { text })\n\t\t},\n\n\t\t/**\n\t\t * Read the messages again when the page refreshes (a dialog sent one).\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onPageRefresh() {\n\t\t\tawait Promise.all([this.loadSource(), this.loadBadge()])\n\t\t},\n\n\t\t/**\n\t\t * Read the threads whose latest status `statusBadge` shows\n\t\t * (`{ source: { register, schema, filter?, limit? }, sortField?, path?, map? }`).\n\t\t * A filter whose token does not resolve, or a failed read, shows no badge.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-reply-tools/specs/conversation/spec.md#requirement-a-conversation-shows-the-latest-thread-status-and-a-status-can-open-a-follow-up\n\t\t */\n\t\tasync loadBadge() {\n\t\t\tconst source = this.content?.statusBadge?.source\n\t\t\tif (!source || !source.register || !source.schema) {\n\t\t\t\tthis.badgeRows = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst filter = resolveDeepTokens(source.filter || {}, this.tokenCtx)\n\t\t\tif (hasUnresolvedDeepTokens(filter) || Object.values(filter).some((value) => value === '' || value === null || value === undefined)) {\n\t\t\t\tthis.badgeRows = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst rows = await fetchReferenceObjects({ register: source.register, schema: source.schema, filter, limit: source.limit || 50 })\n\t\t\t\tthis.badgeRows = Array.isArray(rows) ? rows : []\n\t\t\t} catch {\n\t\t\t\tthis.badgeRows = []\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The stored messages with the side their list gives them: one list\n\t\t * (`field` or `source`), or several merged (`fields`).\n\t\t *\n\t\t * @return {Array<{message: object, side: string, key: string}>} The messages.\n\t\t * @spec openspec/changes/conversation-reply-tools/specs/conversation/spec.md#requirement-a-conversation-merges-several-lists-of-the-record\n\t\t */\n\t\trawMessages() {\n\t\t\tconst c = this.content || {}\n\t\t\tconst lists = !this.source && Array.isArray(c.fields) && c.fields.length > 0\n\t\t\t\t? c.fields.filter((entry) => entry && typeof entry.field === 'string').map((entry) => ({ list: readPath(this.objectData || {}, entry.field), side: entry.side === 'us' ? 'us' : 'them', prefix: entry.field }))\n\t\t\t\t: [{ list: this.source ? this.listed : readPath(this.objectData || {}, c.field || 'messages'), side: '', prefix: 'message' }]\n\t\t\treturn lists.flatMap(({ list, side, prefix }) => (Array.isArray(list) ? list : [])\n\t\t\t\t.filter((message) => message && typeof message === 'object')\n\t\t\t\t.map((message, index) => ({ message, side, key: String(message.id ?? `${prefix}-${index}`) })))\n\t\t},\n\n\t\t/**\n\t\t * Whether a message action applies to a message (`when`).\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} message The stored message.\n\t\t * @return {boolean}\n\t\t */\n\t\tactionApplies(action, message) {\n\t\t\tconst conditions = [].concat(action.when || [])\n\t\t\treturn conditions.every((when) => {\n\t\t\t\tif (!when || typeof when !== 'object' || typeof when.field !== 'string') {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\tconst value = readPath(message, when.field)\n\t\t\t\tif (when.empty === true) {\n\t\t\t\t\treturn value === undefined || value === null || value === ''\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(when.in)) {\n\t\t\t\t\treturn when.in.map(String).includes(String(value))\n\t\t\t\t}\n\t\t\t\treturn String(value) === String(when.equals)\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The reply options at their defaults.\n\t\t *\n\t\t * @return {object} Values by key.\n\t\t */\n\t\tinitialReplyValues() {\n\t\t\tconst list = Array.isArray(this.content?.replyOptions) ? this.content.replyOptions : []\n\t\t\treturn Object.fromEntries(list.filter((option) => option && option.key).map((option) => [option.key, option.default === true]))\n\t\t},\n\n\t\t/**\n\t\t * Put a picked template's text in the reply box.\n\t\t *\n\t\t * @param {object|null} option The template option.\n\t\t * @param {(text: string) => void} setDraft The thread's draft setter.\n\t\t * @return {void}\n\t\t */\n\t\tapplyTemplate(option, setDraft) {\n\t\t\tif (!option || !option.values) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst text = option.values[this.templates.textField || 'text']\n\t\t\tif (typeof text === 'string') {\n\t\t\t\tsetDraft(text)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run a message action: call its endpoint with the message's fields,\n\t\t * then read the messages again.\n\t\t *\n\t\t * @param {{action: string, message: string}} event Which action on which message.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-reply-tools/specs/conversation/spec.md#requirement-a-message-carries-its-status-and-actions\n\t\t */\n\t\tasync onMessageAction({ action: actionId, message: key }) {\n\t\t\tconst action = this.messageActions.find((entry) => entry.id === actionId)\n\t\t\tconst stored = this.rawMessages().find((entry) => entry.key === key)\n\t\t\tif (!action || !stored || this.acting) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.actionError = ''\n\t\t\tthis.acting = `${actionId}|${key}`\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([import('@nextcloud/axios'), import('@nextcloud/router')])\n\t\t\t\tconst path = action.endpoint\n\t\t\t\t\t.replace(/@objectId/g, encodeURIComponent(String(this.objectId ?? '')))\n\t\t\t\t\t.replace(/\\{([\\w.]+)\\}/g, (_m, field) => encodeURIComponent(String(readPath(stored.message, field) ?? '')))\n\t\t\t\tconst response = await axios.request({ method: String(action.method || 'POST').toLowerCase(), url: generateUrl(path) })\n\t\t\t\tif (await this.followUp(action, response?.data)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst refusal = this.actionRefusal(action, response?.data)\n\t\t\t\tif (refusal) {\n\t\t\t\t\tthis.actionError = refusal\n\t\t\t\t}\n\t\t\t\tawait this.loadSource()\n\t\t\t} catch (error) {\n\t\t\t\tif (await this.followUp(action, error?.response?.data)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.actionError = this.actionRefusal(action, error?.response?.data) || this.tr(action.errorText || 'The action failed.')\n\t\t\t} finally {\n\t\t\t\tthis.acting = ''\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run the follow-up action a message action's answer asks for: the\n\t\t * status at `errors.path` (default `status`) looked up in `onStatus`,\n\t\t * dispatched like `headerAction`, tokens resolved against the record.\n\t\t *\n\t\t * @param {object} action The message action.\n\t\t * @param {object|undefined} answer The response body.\n\t\t * @return {Promise<boolean>} True when a follow-up ran.\n\t\t * @spec openspec/changes/conversation-reply-tools/specs/conversation/spec.md#requirement-a-conversation-shows-the-latest-thread-status-and-a-status-can-open-a-follow-up\n\t\t */\n\t\tasync followUp(action, answer) {\n\t\t\tconst map = action.onStatus\n\t\t\tif (!map || typeof map !== 'object' || !answer || typeof answer !== 'object') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst status = readPath(answer, action.errors?.path || 'status')\n\t\t\tconst next = status === undefined || status === null ? null : map[String(status)]\n\t\t\tif (!next || typeof next !== 'object') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst resolved = resolveDeepTokens(next, this.tokenCtx)\n\t\t\ttry {\n\t\t\t\tawait (typeof this.cnDispatchAction === 'function'\n\t\t\t\t\t? this.cnDispatchAction(resolved)\n\t\t\t\t\t: dispatchAction(resolved, { router: this.$router || null }))\n\t\t\t} catch {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t},\n\n\t\t/**\n\t\t * The text a message action's answer names, by `errors` (`{ path, map,\n\t\t * ok? }`): the status at `path` mapped to a text. A status listed in `ok`\n\t\t * (default `[\"sent\", \"ok\"]`) is no refusal.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object|undefined} answer The response body.\n\t\t * @return {string} The text, '' for none.\n\t\t */\n\t\tactionRefusal(action, answer) {\n\t\t\tconst errors = action.errors\n\t\t\tif (!errors || typeof errors !== 'object' || !answer || typeof answer !== 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst status = readPath(answer, errors.path || 'status')\n\t\t\tif (status === undefined || status === null || (errors.ok || ['sent', 'ok']).map(String).includes(String(status))) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst text = (errors.map || {})[String(status)] || errors.default\n\t\t\treturn text ? this.tr(text) : ''\n\t\t},\n\n\t\t/**\n\t\t * Who wrote a message: `usAuthorField` / `themAuthorField` for its\n\t\t * side, else `senderField` (`authorField`). A field written\n\t\t * `@object.<path>` reads the bound record (the case's requester on an\n\t\t * incoming message). With `usAuthorFormat` / `themAuthorFormat` set to\n\t\t * `user` the value is a user id, shown by its display name.\n\t\t *\n\t\t * @param {object} message The message.\n\t\t * @param {string} side `us` or `them`.\n\t\t * @return {string} The author, or '' when the message names none.\n\t\t * @spec openspec/changes/conversation-board-bubble/specs/conversation-source/spec.md#requirement-a-message-names-its-author-per-side-its-direction-and-a-note\n\t\t */\n\t\tauthorOf(message, side) {\n\t\t\tconst c = this.content || {}\n\t\t\tconst field = (side === 'us' ? c.usAuthorField : c.themAuthorField) || c.senderField || c.authorField || 'author'\n\t\t\tconst value = typeof field === 'string' && field.startsWith('@object.')\n\t\t\t\t? readPath(this.objectData || {}, field.slice('@object.'.length))\n\t\t\t\t: readPath(message, field)\n\t\t\tconst text = this.textOf(value)\n\t\t\tconst format = side === 'us' ? c.usAuthorFormat : c.themAuthorFormat\n\t\t\treturn format === 'user' && text !== '' ? (userDisplayName(text) || text) : text\n\t\t},\n\n\t\t/**\n\t\t * @param {unknown} value A stored value.\n\t\t * @return {string} It as text, or '' for none.\n\t\t */\n\t\ttextOf(value) {\n\t\t\treturn value === undefined || value === null || typeof value === 'object' ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * Translate through the app's translate.\n\t\t *\n\t\t * @param {string} key The source string.\n\t\t * @return {string}\n\t\t */\n\t\ttr(key) {\n\t\t\treturn key && typeof this.cnTranslate === 'function' ? this.cnTranslate(key) : (key || '')\n\t\t},\n\n\t\t/**\n\t\t * Read the messages from `source`. A filter whose token does not\n\t\t * resolve sends no request; a failed read leaves the thread empty.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-source/specs/conversation-source/spec.md#requirement-a-conversation-reads-its-messages-from-a-list-and-maps-their-parts\n\t\t */\n\t\tasync loadSource() {\n\t\t\tif (!this.source) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst raw = this.source.filter || {}\n\t\t\tconst filter = resolveDeepTokens(raw, this.tokenCtx)\n\t\t\tconst emptied = Object.keys(raw).some((key) => typeof raw[key] === 'string' && raw[key].startsWith('@') && (filter[key] === '' || filter[key] === null || filter[key] === undefined))\n\t\t\tif (emptied || hasUnresolvedDeepTokens(filter)) {\n\t\t\t\tthis.listed = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tthis.listed = await fetchReferenceObjects({ register: this.source.register, schema: this.source.schema, filter, limit: this.source.limit || 200 })\n\t\t\t\tthis.sentHere = []\n\t\t\t} catch {\n\t\t\t\tthis.listed = []\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 * Run `replyAction` with the reply, when there is one; the endpoint\n\t\t * path is the thread's own.\n\t\t *\n\t\t * @param {string} text The reply.\n\t\t * @param {object} [extras] The reply option's state, `{ [key]: boolean }`.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/conversation-source/specs/conversation-source/spec.md#requirement-a-reply-can-run-an-app-action\n\t\t * @spec openspec/changes/conversation-reply-option/specs/conversation-source/spec.md#requirement-a-reply-can-carry-a-hint-and-an-option\n\t\t */\n\t\tasync onSend(text, extras = {}) {\n\t\t\tif (!this.replyAction) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst resolved = resolveDeepTokens(this.replyAction, this.tokenCtx)\n\t\t\tconst options = this.replyOptions.length > 0 ? { options: { ...this.replyValues } } : {}\n\t\t\tconst action = { ...resolved, args: [{ text, objectId: this.objectId, ...extras, ...options }], props: { ...(resolved.props || {}), text, ...extras, ...options } }\n\t\t\tconst result = typeof this.cnDispatchAction === 'function'\n\t\t\t\t? this.cnDispatchAction(action)\n\t\t\t\t: dispatchAction(action, { router: this.$router || null })\n\t\t\ttry {\n\t\t\t\tconst outcome = await result\n\t\t\t\tif (outcome === false) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.source) {\n\t\t\t\tawait this.loadSource()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.onSent({ text })\n\t\t},\n\n\t\t/**\n\t\t * Run `headerAction` with the record id, then read the source again.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onHeaderAction() {\n\t\t\tif (!this.headerAction) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst { label, icon, ...rest } = resolveDeepTokens(this.headerAction, this.tokenCtx)\n\t\t\tconst action = { ...rest, args: [{ objectId: this.objectId }] }\n\t\t\ttry {\n\t\t\t\tconst outcome = await (typeof this.cnDispatchAction === 'function'\n\t\t\t\t\t? this.cnDispatchAction(action)\n\t\t\t\t\t: dispatchAction(action, { router: this.$router || null }))\n\t\t\t\tif (outcome === false) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadSource()\n\t\t},\n\n\t\t/**\n\t\t * Show an accepted reply at once, without waiting for the record.\n\t\t *\n\t\t * @param {object} data The endpoint's response.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-conversation-thread\n\t\t */\n\t\tonSent(data) {\n\t\t\tconst text = data?.message ?? data?.text\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.draftUrl) {\n\t\t\t\tthis.storeDraft('')\n\t\t\t}\n\t\t\tthis.sentHere.push({\n\t\t\t\tid: `sent-${this.sentHere.length}`,\n\t\t\t\ttime: new Date().toISOString(),\n\t\t\t\ttext,\n\t\t\t\tside: 'us',\n\t\t\t})\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-conversation-widget__badge {\n\tpadding: 2px 10px;\n\tborder-radius: var(--border-radius-pill);\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-conversation-widget__error {\n\tcolor: var(--color-error-text, var(--color-error));\n\tmargin: calc(2 * var(--default-grid-baseline)) 0 0;\n}\n\n.cn-case-widget-card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: calc(5 * var(--default-grid-baseline));\n}\n\n.cn-conversation-widget__draft-status {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n</style>\n"],"names":["CnConversationThread","CnIcon","CnTemplateSelect","t"],"mappings":"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"}