@conduction/nextcloud-vue 2.148.0 → 2.149.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +24 -7
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +12 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +2 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js +23 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +34 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue.js +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue.js +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js +64 -8
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js.map +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js +14 -4
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +26 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +10 -2
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +84 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +61 -33
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +49 -2
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +90 -59
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue2.js +3 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +10 -0
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +11 -0
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +28 -21
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +3 -15
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +123 -115
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +4 -0
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +2 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +2 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +677 -444
- package/dist/nextcloud-vue.cjs.js +1336 -942
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +677 -444
- package/l10n/en.json +2 -1
- package/l10n/nl.json +2 -1
- package/package.json +1 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +24 -7
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +13 -1
- package/src/components/CnChecklistRunWidget/CnChecklistRunWidget.vue +29 -2
- package/src/components/CnDataTable/CnDataTable.vue +34 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +6 -1
- package/src/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue +1 -0
- package/src/components/CnDuplicateWarning/CnDuplicateWarning.vue +74 -10
- package/src/components/CnFactsWidget/CnFactsWidget.vue +35 -3
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +131 -3
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +103 -5
- package/src/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue +3 -1
- package/src/components/CnNotesCard/CnNotesCard.vue +10 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +16 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +1 -1
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +19 -19
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +4 -0
- package/src/css/dialog.css +17 -0
- package/src/css/look-board-detail.css +52 -3
- package/src/css/look-board-index.css +37 -1
- package/src/css/look-board.css +45 -5
- package/src/css/table.css +5 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnNotesCard.vue3.js","sources":["../../../../src/components/CnNotesCard/CnNotesCard.vue?vue&type=template&id=25437d6c&lang.js"],"sourcesContent":["<!--\n CnNotesCard — Inline notes card for detail pages.\n\n Displays up to 5 recent notes with author, content, and timestamp.\n Includes an add-note form and integrates CnUserActionMenu on author names.\n Wraps CnDetailCard for consistent styling.\n-->\n<template>\n\t<CnDetailCard :title=\"titleLabel\"\n\t\t:icon=\"CommentTextOutline\"\n\t\t:collapsible=\"collapsible\"\n\t\t:chromeless=\"chromeless\">\n\t\t<template v-if=\"composerBehindButton\" #actions>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:aria-expanded=\"composerShown ? 'true' : 'false'\"\n\t\t\t\tdata-testid=\"cn-notes-card-open-composer\"\n\t\t\t\t@click=\"composerOpen = !composerOpen\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NotePlusOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ addNoteLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t\t<div class=\"cn-notes-card\">\n\t\t\t<!-- Add note input -->\n\t\t\t<div v-if=\"!unavailable && composerShown\" class=\"cn-notes-card__add-form\">\n\t\t\t\t<!-- Replying: the form says to whom; a reply to a reply goes to the top of its thread. -->\n\t\t\t\t<p\n\t\t\t\t\tv-if=\"replyTo\"\n\t\t\t\t\tclass=\"cn-notes-card__replying\"\n\t\t\t\t\trole=\"status\"\n\t\t\t\t\tdata-testid=\"cn-notes-card-replying\">\n\t\t\t\t\t{{ replyingLabel }}\n\t\t\t\t\t<NcButton variant=\"tertiary\" @click=\"replyTo = null\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</p>\n\t\t\t\t<CnNoteComposer\n\t\t\t\t\tclass=\"cn-notes-card__textarea\"\n\t\t\t\t\t:modelValue=\"newNoteText\"\n\t\t\t\t\t:placeholder=\"addNotePlaceholder\"\n\t\t\t\t\t:register=\"isFileSource || isSourceMode ? '' : registerId\"\n\t\t\t\t\t:schema=\"isFileSource || isSourceMode ? '' : schemaId\"\n\t\t\t\t\t:objectId=\"isFileSource || isSourceMode ? '' : objectId\"\n\t\t\t\t\t:apiBase=\"apiBase\"\n\t\t\t\t\t@update:modelValue=\"newNoteText = $event\"\n\t\t\t\t\t@submit=\"submitNote\" />\n\t\t\t\t<!-- Internal or public, chosen before the note is written (only when the host says the caller may set it). -->\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\tv-if=\"visibilityToggleShown\"\n\t\t\t\t\t:modelValue=\"newNoteVisibility === 'public'\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\tdata-testid=\"cn-notes-card-visibility-switch\"\n\t\t\t\t\t@update:modelValue=\"(on) => newNoteVisibility = on ? 'public' : 'internal'\">\n\t\t\t\t\t{{ publicSwitchLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t:disabled=\"!newNoteText.trim() || noteSaving\"\n\t\t\t\t\t@click=\"submitNote\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Send :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ addNoteLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\n\t\t\t<!-- Loading state -->\n\t\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t\t<!-- Empty state -->\n\t\t\t<div v-else-if=\"unavailable\" class=\"cn-notes-card__empty\" data-testid=\"cn-notes-card-unavailable\">\n\t\t\t\t{{ unavailableLabel }}\n\t\t\t</div>\n\t\t\t<p v-else-if=\"failed\"\n\t\t\t\tclass=\"cn-notes-card__empty\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-notes-card-failed\">\n\t\t\t\t{{ failedLabel }}\n\t\t\t</p>\n\t\t\t<div v-else-if=\"allNotes.length === 0\" class=\"cn-notes-card__empty\">\n\t\t\t\t{{ noNotesLabel }}\n\t\t\t</div>\n\n\t\t\t<!-- Notes list (last 5), threaded: a note, then its replies. -->\n\t\t\t<div v-else class=\"cn-notes-card__list\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"thread in threads\"\n\t\t\t\t\t:key=\"thread.note.id\"\n\t\t\t\t\tclass=\"cn-notes-card__thread\"\n\t\t\t\t\trole=\"group\"\n\t\t\t\t\t:aria-label=\"threadLabel(thread.note)\">\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-for=\"row in threadRows(thread)\"\n\t\t\t\t\t\t:key=\"row.note.id\"\n\t\t\t\t\t\tclass=\"cn-notes-card__note\"\n\t\t\t\t\t\t:class=\"{ 'cn-notes-card__note--reply': row.isReply }\">\n\t\t\t\t\t\t<span class=\"cn-notes-card__initials\" aria-hidden=\"true\">{{ initialsOf(getNoteAuthorName(row.note)) }}</span>\n\t\t\t\t\t\t<div class=\"cn-notes-card__note-header\">\n\t\t\t\t\t\t\t<CnUserActionMenu\n\t\t\t\t\t\t\t\tv-if=\"!isCurrentUser(row.note)\"\n\t\t\t\t\t\t\t\t:userId=\"getNoteAuthorId(row.note)\"\n\t\t\t\t\t\t\t\t:displayName=\"getNoteAuthorName(row.note)\">\n\t\t\t\t\t\t\t\t<strong class=\"cn-notes-card__author\">{{ getNoteAuthorName(row.note) }}</strong>\n\t\t\t\t\t\t\t</CnUserActionMenu>\n\t\t\t\t\t\t\t<strong v-else class=\"cn-notes-card__author cn-notes-card__author--self\">\n\t\t\t\t\t\t\t\t{{ getNoteAuthorName(row.note) }}\n\t\t\t\t\t\t\t</strong>\n\t\t\t\t\t\t\t<span class=\"cn-notes-card__time\">{{ formatDate(row.note.creationDateTime || row.note.created || row.note.createdAt) }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"visibilityShown\" class=\"cn-notes-card__visibility\">\n\t\t\t\t\t\t\t<CnVisibilityChip :visibility=\"row.note.visibility\" />\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tv-if=\"visibilityToggleShown\"\n\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-notes-card-visibility-toggle\"\n\t\t\t\t\t\t\t\t@click=\"toggleVisibility(row.note)\">\n\t\t\t\t\t\t\t\t{{ noteVisibility(row.note) === 'public' ? makeInternalLabel : makePublicLabel }}\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p v-if=\"row.quote\" class=\"cn-notes-card__quote\" data-testid=\"cn-notes-card-quote\">\n\t\t\t\t\t\t\t{{ row.quote }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p class=\"cn-notes-card__body\">\n\t\t\t\t\t\t\t<CnNoteBody :message=\"row.note.message || row.note.content || ''\" :record=\"isFileSource || isSourceMode ? null : record\" />\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canReply\"\n\t\t\t\t\t\t\tclass=\"cn-notes-card__reply-btn\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t:aria-label=\"replyAria(row.note)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-notes-card-reply\"\n\t\t\t\t\t\t\t@click=\"replyTo = row.note\">\n\t\t\t\t\t\t\t{{ replyLabel }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canDeleteNote(row.note)\"\n\t\t\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\t\t\tclass=\"cn-notes-card__delete-btn\"\n\t\t\t\t\t\t\t:aria-label=\"deleteLabel\"\n\t\t\t\t\t\t\t@click=\"confirmDelete(row.note)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Delete :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Footer: \"Show all\" link -->\n\t\t<template v-if=\"allNotes.length > maxDisplay\" #footer>\n\t\t\t<button\n\t\t\t\tclass=\"cn-notes-card__show-all\"\n\t\t\t\t@click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ allNotes.length }})\n\t\t\t</button>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport CommentTextOutline from 'vue-material-design-icons/CommentTextOutline.vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport NotePlusOutline from 'vue-material-design-icons/NotePlusOutline.vue'\nimport Send from 'vue-material-design-icons/Send.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport CnNoteBody from '../CnNoteBody/CnNoteBody.vue'\nimport CnNoteComposer from '../CnNoteComposer/CnNoteComposer.vue'\nimport CnUserActionMenu from '../CnUserActionMenu/CnUserActionMenu.vue'\nimport CnVisibilityChip from '../CnVisibilityChip/CnVisibilityChip.vue'\nimport { useFileComments } from '../../composables/useFileComments.js'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { initialsOf } from '../../utils/initials.js'\nimport { leafSourceUrl } from '../../utils/leafSourceUrl.js'\nimport { extractMentionedGroupIds, extractMentionedIds } from '../../utils/mentions.js'\nimport { quoteFor, supportsReplies, threadNotes, threadRootId } from '../../utils/noteThreads.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnNotesCard — Inline notes widget for detail pages.\n *\n * Shows up to 5 recent notes with add/delete functionality.\n * Integrates CnUserActionMenu on author names for quick communication.\n *\n * Basic usage\n * ```vue\n * <CnNotesCard\n * register-id=\"uuid-register\"\n * schema-id=\"uuid-schema\"\n * object-id=\"uuid-object\" />\n * ```\n *\n * With sidebar sync\n * ```vue\n * <CnNotesCard\n * register-id=\"reg\"\n * schema-id=\"schema\"\n * object-id=\"obj\"\n * @note-added=\"refreshNotes\"\n * @note-deleted=\"refreshNotes\"\n * @show-all=\"openSidebarNotesTab\" />\n * ```\n *\n * @event note-added Emitted after a new note is successfully persisted. Payload: the created note object.\n * @event note-deleted Emitted after a note is successfully deleted. Payload: the deleted note ID.\n * @event visibility-changed Emitted after a note's visibility was changed. Payload: `{ id, visibility }`.\n * @event mention Emitted after a note that mentions someone was added. Payload: `{ objectId, register, schema, noteId, mentionedUserIds }`, plus `mentionedGroupIds` when a group (`@\"group/<gid>\"`) is mentioned. nc-vue notifies nobody; the listener does.\n * @event show-all Emitted when the user clicks the \"Show all\" button — parents typically open a full notes sidebar tab.\n */\n/**\n * The server's own sentence on a refused note write, '' when it gave none.\n *\n * @param {Response} response The refused response.\n * @return {Promise<string>} The message.\n */\nasync function refusalMessage(response) {\n\ttry {\n\t\tconst data = await response.json()\n\t\tconst message = serverErrorMessage({ message: '-', response: { data } })\n\t\treturn message === '-' ? '' : message\n\t} catch {\n\t\treturn ''\n\t}\n}\n\nexport default {\n\tname: 'CnNotesCard',\n\n\tcomponents: {\n\t\tCnDetailCard,\n\t\tCnNoteBody,\n\t\tCnNoteComposer,\n\t\tCnUserActionMenu,\n\t\tCnVisibilityChip,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcLoadingIcon,\n\t\tNotePlusOutline,\n\t\tSend,\n\t\tDelete,\n\t},\n\n\tprops: {\n\t\t/** OpenRegister register ID */\n\t\tregisterId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema ID */\n\t\tschemaId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Object UUID */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Show the notes of a plain Nextcloud file instead of an OpenRegister\n\t\t * object: the file's id. Used when no `objectId` is given; the notes\n\t\t * are the file's comments (`/remote.php/dav/comments/files/{fileId}`),\n\t\t * the same ones the Files sidebar shows.\n\t\t */\n\t\tfileId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Base API URL for OpenRegister */\n\t\tapiBase: {\n\t\t\ttype: String,\n\t\t\tdefault: '/apps/openregister/api',\n\t\t},\n\n\t\t/**\n\t\t * Read the notes of something that is not an OpenRegister object:\n\t\t * `{ kind: 'flow-task', id }` reads `${apiBase}/flow-tasks/{id}/notes`.\n\t\t * `id` may be left out or written `@objectId` for `objectId`.\n\t\t *\n\t\t * @type {{kind: string, id?: (string|number)}|null}\n\t\t */\n\t\tsource: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * A notes URL that replaces the object's own: the list and the add go\n\t\t * to it, a delete to `{endpoint}/{noteId}`. `{id}` is filled with the\n\t\t * source's id or `objectId`.\n\t\t */\n\t\tendpoint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Maximum number of notes to display */\n\t\tmaxDisplay: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5,\n\t\t},\n\n\t\t/** Whether the card is collapsible */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Render the notes body without the surrounding CnDetailCard.\n\t\t *\n\t\t * Set when a surface already supplies the card and the title, such as a\n\t\t * tab panel whose open tab names the panel. Leaving the card on there\n\t\t * nests a card inside a card and shows the label twice.\n\t\t */\n\t\tchromeless: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Where the add form lives: `inline` (default) keeps it open above the\n\t\t * notes; `button` puts it behind an \"Add note\" button in the card's\n\t\t * header (DqTaak \"Notities\"), and closes it again once the note is\n\t\t * saved. A reply opens it either way. Without the card's header\n\t\t * (`chromeless`) the form stays inline.\n\t\t *\n\t\t * @spec openspec/changes/notes-card-composer-button/specs/notes-card-composer-button/spec.md#requirement-a-notes-card-can-keep-its-composer-behind-a-header-button\n\t\t */\n\t\tcomposer: {\n\t\t\ttype: String,\n\t\t\tdefault: 'inline',\n\t\t\tvalidator: (v) => ['inline', 'button'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Show a chip on every note reading internal or public. A note without a\n\t\t * value reads as internal. Off by default, so a host that passes nothing\n\t\t * renders the card as before. Not used for a file source (file comments\n\t\t * carry no flag).\n\t\t */\n\t\tshowVisibility: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the caller may set visibility on this object: the answer the\n\t\t * server gives for `update` on it. The host passes it; the card never\n\t\t * infers it from the current user. When true the card offers the\n\t\t * public switch in the add-note form and a toggle on each note.\n\t\t */\n\t\tcanSetVisibility: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t// --- Pre-translated labels ---\n\t\t/** Card header title. */\n\t\ttitleLabel: { type: String, default: () => t('nextcloud-vue', 'Notes') },\n\t\t/** Label for the submit button that creates a new note. */\n\t\taddNoteLabel: { type: String, default: () => t('nextcloud-vue', 'Add note') },\n\t\t/** Placeholder shown inside the new-note textarea before any input. */\n\t\taddNotePlaceholder: { type: String, default: () => t('nextcloud-vue', 'Write a note…') },\n\t\t/** Empty-state text shown when the object has zero notes. */\n\t\tnoNotesLabel: { type: String, default: () => t('nextcloud-vue', 'No notes yet') },\n\t\t/** Label for the \"Show all\" button rendered when the note list is truncated. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/** Text shown instead of the notes when Nextcloud refuses a file's comments (no access). */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'Notes are not available for this file') },\n\t\t/** Label of the add-note switch that makes the note public. */\n\t\tpublicSwitchLabel: { type: String, default: () => t('nextcloud-vue', 'Public (visible to the customer)') },\n\t\t/** Label of the per-note action that makes an internal note public. */\n\t\tmakePublicLabel: { type: String, default: () => t('nextcloud-vue', 'Make public') },\n\t\t/** Label of the per-note action that makes a public note internal. */\n\t\tmakeInternalLabel: { type: String, default: () => t('nextcloud-vue', 'Make internal') },\n\t\t/** Label of the Reply button (shown only when the backend supports replies). */\n\t\treplyLabel: { type: String, default: () => t('nextcloud-vue', 'Reply') },\n\t\t/** Aria label for the per-note delete icon button. */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete note') },\n\t\t/** Text shown when a `source` or `endpoint` read failed. */\n\t\tfailedLabel: { type: String, default: () => t('nextcloud-vue', 'The notes could not be loaded') },\n\t},\n\n\temits: ['mention', 'note-added', 'note-deleted', 'show-all', 'visibility-changed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tCommentTextOutline: markRaw(CommentTextOutline),\n\t\t\tallNotes: [],\n\t\t\tloading: false,\n\t\t\tnewNoteText: '',\n\t\t\t/** Whether the add form is open while `composer` is `button`. */\n\t\t\tcomposerOpen: false,\n\t\t\t/** Visibility the next note is written with (only sent when the caller may set it). */\n\t\t\tnewNoteVisibility: 'internal',\n\t\t\tnoteSaving: false,\n\t\t\tdeleteConfirmId: null,\n\t\t\t/** The file source answered 403 or 404: no notes and no add field. */\n\t\t\tunavailable: false,\n\t\t\t/** A `source` or `endpoint` read failed: said, rather than shown as no notes. */\n\t\t\tfailed: false,\n\t\t\t/** The note a reply is being written to, or null. */\n\t\t\treplyTo: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {boolean} Whether the add form sits behind the header's button. */\n\t\tcomposerBehindButton() {\n\t\t\treturn this.composer === 'button' && !this.chromeless && !this.unavailable\n\t\t},\n\n\t\t/** @return {boolean} Whether the add form shows. */\n\t\tcomposerShown() {\n\t\t\treturn !this.composerBehindButton || this.composerOpen || Boolean(this.replyTo)\n\t\t},\n\n\t\t/** Chips are shown: the host asked for them (or lets the caller set visibility) and the notes are object notes. */\n\t\tvisibilityShown() {\n\t\t\treturn (this.showVisibility || this.canSetVisibility) && !this.isFileSource\n\t\t},\n\n\t\t/** The switch and the per-note toggle are offered: only when the host says the caller may set it. */\n\t\tvisibilityToggleShown() {\n\t\t\treturn this.canSetVisibility && !this.isFileSource\n\t\t},\n\n\t\t/**\n\t\t * The notes URL a `source` or `endpoint` names, '' while its record id\n\t\t * is unknown, or null when the card reads an object.\n\t\t *\n\t\t * @return {string|null}\n\t\t * @spec openspec/changes/leaf-cards-read-a-source/specs/leaf-cards-read-a-source/spec.md#requirement-a-leaf-card-reads-a-source-or-an-endpoint\n\t\t */\n\t\tsourceUrl() {\n\t\t\treturn leafSourceUrl({ source: this.source, endpoint: this.endpoint, apiBase: this.apiBase, objectId: this.objectId }, 'notes')\n\t\t},\n\n\t\t/** The notes come from a `source` or `endpoint`, not from an object. */\n\t\tisSourceMode() {\n\t\t\treturn this.sourceUrl !== null\n\t\t},\n\n\t\t/** @return {string} The notes URL the list, add and delete use. */\n\t\tnotesUrl() {\n\t\t\tif (this.isSourceMode) {\n\t\t\t\treturn this.sourceUrl\n\t\t\t}\n\t\t\treturn `${this.apiBase}/objects/${this.registerId}/${this.schemaId}/${this.objectId}/notes`\n\t\t},\n\n\t\t/** The file source applies: a file id and no object. */\n\t\tisFileSource() {\n\t\t\treturn this.fileId !== null && this.fileId !== undefined && this.fileId !== '' && !this.objectId\n\t\t},\n\n\t\t/** @return {{apiBase: string, register: string, schema: string, objectId: string}} Where this record's files live, for pasted images. */\n\t\trecord() {\n\t\t\treturn { apiBase: this.apiBase, register: this.registerId, schema: this.schemaId, objectId: this.objectId }\n\t\t},\n\n\t\t/** @return {boolean} Whether the backend supports replies: its notes carry a `parentId` key. Not for a file's comments. */\n\t\tcanReply() {\n\t\t\treturn !this.isFileSource && supportsReplies(this.allNotes)\n\t\t},\n\n\t\t/** @return {Array<{note: object, replies: object[]}>} The shown notes as threads. */\n\t\tthreads() {\n\t\t\treturn threadNotes(this.displayedNotes)\n\t\t},\n\n\t\t/** @return {string} The line above the form while replying. */\n\t\treplyingLabel() {\n\t\t\treturn this.replyTo ? t('nextcloud-vue', 'Replying to {author}', { author: this.getNoteAuthorName(this.replyTo) }) : ''\n\t\t},\n\n\t\tdisplayedNotes() {\n\t\t\t// Reverse chronological, limited to maxDisplay\n\t\t\tconst sorted = [...this.allNotes].sort((a, b) => {\n\t\t\t\tconst dateA = new Date(a.creationDateTime || a.created || a.createdAt || 0)\n\t\t\t\tconst dateB = new Date(b.creationDateTime || b.created || b.createdAt || 0)\n\t\t\t\treturn dateB - dateA\n\t\t\t})\n\t\t\treturn sorted.slice(0, this.maxDisplay)\n\t\t},\n\t},\n\n\twatch: {\n\t\tfileId: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tif (this.isFileSource) {\n\t\t\t\t\tthis.fetchNotes()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(newId) {\n\t\t\t\tif (newId && this.registerId && this.schemaId && !this.isSourceMode) {\n\t\t\t\t\tthis.fetchNotes()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tsourceUrl: {\n\t\t\timmediate: true,\n\t\t\thandler(url) {\n\t\t\t\tif (typeof url === 'string' && url !== '') {\n\t\t\t\t\tthis.fetchNotes()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A note's visibility; an entry with no value reads as internal.\n\t\t *\n\t\t * @param {object} note The note.\n\t\t * @return {'public'|'internal'} The visibility.\n\t\t */\n\t\tnoteVisibility(note) {\n\t\t\treturn note && note.visibility === 'public' ? 'public' : 'internal'\n\t\t},\n\n\t\t/**\n\t\t * The one place a note write goes out: creating a note and changing its\n\t\t * visibility both send through here, so the value is sent from one spot.\n\t\t *\n\t\t * @param {'POST'|'PATCH'} method The HTTP method.\n\t\t * @param {string} url The notes URL (with the note id for a change).\n\t\t * @param {object} body The JSON body.\n\t\t * @return {Promise<Response>} The response.\n\t\t */\n\t\twriteNote(method, url, body) {\n\t\t\treturn fetch(prefixUrl(url), { method, headers: buildHeaders(), body: JSON.stringify(body) })\n\t\t},\n\n\t\t/**\n\t\t * Flip a note between internal and public.\n\t\t *\n\t\t * @param {object} note The note.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync toggleVisibility(note) {\n\t\t\tif (!this.visibilityToggleShown) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = this.noteVisibility(note) === 'public' ? 'internal' : 'public'\n\t\t\ttry {\n\t\t\t\tconst url = `${this.notesUrl}/${note.id}`\n\t\t\t\tconst response = await this.writeNote('PATCH', url, { visibility: next })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.allNotes = this.allNotes.map((n) => (n.id === note.id ? { ...n, visibility: next } : n))\n\t\t\t\t\t/** @event visibility-changed Emitted after a note's visibility was changed. Payload: `{ id, visibility }`. */\n\t\t\t\t\tthis.$emit('visibility-changed', { id: note.id, visibility: next })\n\t\t\t\t} else {\n\t\t\t\t\tthis.showError('Failed to change visibility')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error('CnNotesCard: Failed to change visibility', err)\n\t\t\t\tthis.showError('Failed to change visibility')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The rows of one thread: the note, then its replies. A reply whose parent\n\t\t * is far up the list carries a one-line quote of it.\n\t\t *\n\t\t * @param {{note: object, replies: object[]}} thread The thread.\n\t\t * @return {Array<{note: object, isReply: boolean, quote: string}>} The rows.\n\t\t */\n\t\tthreadRows(thread) {\n\t\t\tconst flat = this.threads.flatMap((t2) => [t2.note, ...t2.replies])\n\t\t\treturn [\n\t\t\t\t{ note: thread.note, isReply: false, quote: '' },\n\t\t\t\t...thread.replies.map((reply) => ({ note: reply, isReply: true, quote: quoteFor(reply, flat) })),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note A top-level note.\n\t\t * @return {string} The name of its thread for assistive technology.\n\t\t */\n\t\tthreadLabel(note) {\n\t\t\treturn t('nextcloud-vue', 'Note by {author} and its replies', { author: this.getNoteAuthorName(note) })\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note The note a Reply button answers.\n\t\t * @return {string} The button's accessible name, naming the author.\n\t\t */\n\t\treplyAria(note) {\n\t\t\treturn t('nextcloud-vue', 'Reply to {author}', { author: this.getNoteAuthorName(note) })\n\t\t},\n\n\t\t/**\n\t\t * Tell the host a saved note mentions someone. The payload keeps the\n\t\t * user ids and adds the group ids only when a group is mentioned.\n\t\t *\n\t\t * @param {string} text The saved text.\n\t\t * @param {string|null} noteId The note's id.\n\t\t * @return {void}\n\t\t */\n\t\temitMentionEvent(text, noteId) {\n\t\t\tconst mentionedUserIds = extractMentionedIds(text)\n\t\t\tconst mentionedGroupIds = extractMentionedGroupIds(text)\n\t\t\tif (mentionedUserIds.length === 0 && mentionedGroupIds.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('mention', {\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tregister: this.registerId,\n\t\t\t\tschema: this.schemaId,\n\t\t\t\tnoteId,\n\t\t\t\tmentionedUserIds,\n\t\t\t\t...(mentionedGroupIds.length > 0 ? { mentionedGroupIds } : {}),\n\t\t\t})\n\t\t},\n\n\t\tgetNoteAuthorId(note) {\n\t\t\treturn note.actorId || note.author || ''\n\t\t},\n\n\t\tinitialsOf,\n\n\t\tgetNoteAuthorName(note) {\n\t\t\treturn note.actorDisplayName || note.author || 'Unknown'\n\t\t},\n\n\t\tisCurrentUser(note) {\n\t\t\tif (note.isCurrentUser === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst authorId = this.getNoteAuthorId(note)\n\t\t\tconst currentUser = typeof OC !== 'undefined' ? OC?.currentUser : null\n\t\t\treturn authorId === currentUser\n\t\t},\n\n\t\tcanDeleteNote(note) {\n\t\t\treturn this.isCurrentUser(note)\n\t\t},\n\n\t\tfileComments() {\n\t\t\treturn useFileComments(this.fileId)\n\t\t},\n\n\t\tasync fetchNotes() {\n\t\t\tif (this.isFileSource) {\n\t\t\t\tthis.loading = true\n\t\t\t\tthis.unavailable = false\n\t\t\t\ttry {\n\t\t\t\t\tthis.allNotes = await this.fileComments().list()\n\t\t\t\t} catch (err) {\n\t\t\t\t\tthis.allNotes = []\n\t\t\t\t\tthis.unavailable = err && (err.status === 403 || err.status === 404)\n\t\t\t\t\tif (!this.unavailable) {\n\t\t\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\t\t\tconsole.error('CnNotesCard: Failed to fetch file comments', err)\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tthis.loading = false\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.isSourceMode ? this.notesUrl === '' : (!this.registerId || !this.schemaId || !this.objectId)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.notesUrl), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allNotes = data.results || data || []\n\t\t\t\t} else if (this.isSourceMode) {\n\t\t\t\t\tthis.allNotes = []\n\t\t\t\t\tthis.failed = true\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis.failed = this.isSourceMode\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error('CnNotesCard: Failed to fetch notes', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync submitNote() {\n\t\t\tif (!this.newNoteText.trim() || this.noteSaving) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.noteSaving = true\n\t\t\tif (this.isFileSource) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.fileComments().add(this.newNoteText.trim())\n\t\t\t\t\tthis.composerOpen = false\n\t\t\t\t\tthis.newNoteText = ''\n\t\t\t\t\tawait this.fetchNotes()\n\t\t\t\t\tthis.$emit('note-added')\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\t\tconsole.error('CnNotesCard: Failed to add file comment', err)\n\t\t\t\t\tthis.showError('Failed to add note')\n\t\t\t\t} finally {\n\t\t\t\t\tthis.noteSaving = false\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst url = this.notesUrl\n\t\t\t\tconst body = { message: this.newNoteText.trim() }\n\t\t\t\tif (this.visibilityToggleShown) {\n\t\t\t\t\tbody.visibility = this.newNoteVisibility\n\t\t\t\t}\n\t\t\t\tif (this.replyTo) {\n\t\t\t\t\tbody.parentId = threadRootId(this.replyTo, this.allNotes)\n\t\t\t\t}\n\t\t\t\tconst response = await this.writeNote('POST', url, body)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tlet noteId = null\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst created = await response.json()\n\t\t\t\t\t\tnoteId = (created && (created.id || (created.results && created.results.id))) || null\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Body not JSON: the event still fires with noteId null.\n\t\t\t\t\t}\n\t\t\t\t\tthis.emitMentionEvent(body.message, noteId)\n\t\t\t\t\tthis.replyTo = null\n\t\t\t\t\tthis.composerOpen = false\n\t\t\t\t\tthis.newNoteText = ''\n\t\t\t\t\tthis.newNoteVisibility = 'internal'\n\t\t\t\t\tawait this.fetchNotes()\n\t\t\t\t\tthis.$emit('note-added')\n\t\t\t\t} else {\n\t\t\t\t\tthis.showError(await refusalMessage(response) || 'Failed to add note')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error('CnNotesCard: Failed to add note', err)\n\t\t\t\tthis.showError('Failed to add note')\n\t\t\t} finally {\n\t\t\t\tthis.noteSaving = false\n\t\t\t}\n\t\t},\n\n\t\tasync confirmDelete(note) {\n\t\t\t// Simple inline confirmation — delete directly\n\t\t\tif (this.isFileSource) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.fileComments().remove(note.id)\n\t\t\t\t\tthis.allNotes = this.allNotes.filter((n) => n.id !== note.id)\n\t\t\t\t\tthis.$emit('note-deleted')\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\t\tconsole.error('CnNotesCard: Failed to delete file comment', err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst url = `${this.notesUrl}/${note.id}`\n\t\t\t\tconst response = await fetch(prefixUrl(url), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.allNotes = this.allNotes.filter((n) => n.id !== note.id)\n\t\t\t\t\tthis.$emit('note-deleted')\n\t\t\t\t} else {\n\t\t\t\t\tthis.showError(await refusalMessage(response) || 'Failed to delete note')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error('CnNotesCard: Failed to delete note', err)\n\t\t\t}\n\t\t},\n\n\t\tformatDate(dateStr) {\n\t\t\tif (!dateStr) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(dateStr).toLocaleString(userLocale(), {\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\thour: '2-digit',\n\t\t\t\t\tminute: '2-digit',\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn dateStr\n\t\t\t}\n\t\t},\n\n\t\tshowError(message) {\n\t\t\ttry {\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => {\n\t\t\t\t\tshowError(message)\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error(message)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-notes-card__add-form {\n\tmargin-bottom: 12px;\n}\n\n.cn-notes-card__textarea {\n\twidth: 100%;\n\tmargin-bottom: 8px;\n\tbox-sizing: border-box;\n}\n\n.cn-notes-card__replying {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin: 0 0 4px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-notes-card__note--reply {\n\tmargin-inline-start: 24px;\n}\n\n.cn-notes-card__quote {\n\tmargin: 0 0 2px;\n\tpadding-inline-start: 8px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-notes-card__empty {\n\ttext-align: center;\n\tpadding: 16px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-notes-card__list {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-notes-card__note {\n\tpadding: 10px 0;\n\tborder-bottom: 1px solid var(--color-border);\n\tposition: relative;\n}\n\n.cn-notes-card__note:last-child {\n\tborder-bottom: none;\n}\n\n.cn-notes-card__initials {\n\tdisplay: none;\n}\n\n.cn-notes-card__note-header {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: baseline;\n\tmargin-bottom: 4px;\n}\n\n.cn-notes-card__author {\n\tfont-size: 13px;\n}\n\n.cn-notes-card__author--self {\n\tcolor: var(--color-main-text);\n}\n\n.cn-notes-card__visibility {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin-bottom: 4px;\n}\n\n.cn-notes-card__time {\n\tfont-size: 11px;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n\tmargin-left: 8px;\n}\n\n.cn-notes-card__body {\n\tfont-size: 13px;\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n\tpadding-right: 32px;\n}\n\n/* The note's own class leads so the position outranks NcButton's\n `position: relative`, which loads later at the same weight and put the\n button in the flow under the note. */\n.cn-notes-card__note > .cn-notes-card__delete-btn {\n\tposition: absolute;\n\ttop: 8px;\n\tright: -4px;\n\topacity: 0;\n\ttransition: opacity 0.15s ease;\n}\n\n.cn-notes-card__note:hover > .cn-notes-card__delete-btn,\n.cn-notes-card__note:focus-within > .cn-notes-card__delete-btn {\n\topacity: 1;\n}\n\n.cn-notes-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\tpadding: 0;\n\twidth: 100%;\n\ttext-align: center;\n}\n\n.cn-notes-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_openBlock","_createElementBlock","_createTextVNode","_toDisplayString","_createVNode","_Fragment","_renderList","_normalizeClass","_createElementVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnNotesCard.vue3.js","sources":["../../../../src/components/CnNotesCard/CnNotesCard.vue?vue&type=template&id=23928d29&lang.js"],"sourcesContent":["<!--\n CnNotesCard — Inline notes card for detail pages.\n\n Displays up to 5 recent notes with author, content, and timestamp.\n Includes an add-note form and integrates CnUserActionMenu on author names.\n Wraps CnDetailCard for consistent styling.\n-->\n<template>\n\t<CnDetailCard :title=\"titleLabel\"\n\t\t:icon=\"CommentTextOutline\"\n\t\t:collapsible=\"collapsible\"\n\t\t:chromeless=\"chromeless\">\n\t\t<template v-if=\"composerBehindButton\" #actions>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:aria-expanded=\"composerShown ? 'true' : 'false'\"\n\t\t\t\tdata-testid=\"cn-notes-card-open-composer\"\n\t\t\t\t@click=\"composerOpen = !composerOpen\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NotePlusOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ addNoteLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t\t<div class=\"cn-notes-card\">\n\t\t\t<!-- Add note input -->\n\t\t\t<div v-if=\"!unavailable && composerShown\" class=\"cn-notes-card__add-form\">\n\t\t\t\t<!-- Replying: the form says to whom; a reply to a reply goes to the top of its thread. -->\n\t\t\t\t<p\n\t\t\t\t\tv-if=\"replyTo\"\n\t\t\t\t\tclass=\"cn-notes-card__replying\"\n\t\t\t\t\trole=\"status\"\n\t\t\t\t\tdata-testid=\"cn-notes-card-replying\">\n\t\t\t\t\t{{ replyingLabel }}\n\t\t\t\t\t<NcButton variant=\"tertiary\" @click=\"replyTo = null\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</p>\n\t\t\t\t<CnNoteComposer\n\t\t\t\t\tclass=\"cn-notes-card__textarea\"\n\t\t\t\t\t:modelValue=\"newNoteText\"\n\t\t\t\t\t:placeholder=\"addNotePlaceholder\"\n\t\t\t\t\t:register=\"isFileSource || isSourceMode ? '' : registerId\"\n\t\t\t\t\t:schema=\"isFileSource || isSourceMode ? '' : schemaId\"\n\t\t\t\t\t:objectId=\"isFileSource || isSourceMode ? '' : objectId\"\n\t\t\t\t\t:apiBase=\"apiBase\"\n\t\t\t\t\t@update:modelValue=\"newNoteText = $event\"\n\t\t\t\t\t@submit=\"submitNote\" />\n\t\t\t\t<!-- Internal or public, chosen before the note is written (only when the host says the caller may set it). -->\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\tv-if=\"visibilityToggleShown\"\n\t\t\t\t\t:modelValue=\"newNoteVisibility === 'public'\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\tdata-testid=\"cn-notes-card-visibility-switch\"\n\t\t\t\t\t@update:modelValue=\"(on) => newNoteVisibility = on ? 'public' : 'internal'\">\n\t\t\t\t\t{{ publicSwitchLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t:disabled=\"!newNoteText.trim() || noteSaving\"\n\t\t\t\t\t@click=\"submitNote\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Send :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ addNoteLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\n\t\t\t<!-- Loading state -->\n\t\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t\t<!-- Empty state -->\n\t\t\t<div v-else-if=\"unavailable\" class=\"cn-notes-card__empty\" data-testid=\"cn-notes-card-unavailable\">\n\t\t\t\t{{ unavailableLabel }}\n\t\t\t</div>\n\t\t\t<p v-else-if=\"failed\"\n\t\t\t\tclass=\"cn-notes-card__empty\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-notes-card-failed\">\n\t\t\t\t{{ failedLabel }}\n\t\t\t</p>\n\t\t\t<div v-else-if=\"allNotes.length === 0\" class=\"cn-notes-card__empty\">\n\t\t\t\t{{ noNotesLabel }}\n\t\t\t</div>\n\n\t\t\t<!-- Notes list (last 5), threaded: a note, then its replies. -->\n\t\t\t<div v-else class=\"cn-notes-card__list\">\n\t\t\t\t<div\n\t\t\t\t\tv-for=\"thread in threads\"\n\t\t\t\t\t:key=\"thread.note.id\"\n\t\t\t\t\tclass=\"cn-notes-card__thread\"\n\t\t\t\t\trole=\"group\"\n\t\t\t\t\t:aria-label=\"threadLabel(thread.note)\">\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-for=\"row in threadRows(thread)\"\n\t\t\t\t\t\t:key=\"row.note.id\"\n\t\t\t\t\t\tclass=\"cn-notes-card__note\"\n\t\t\t\t\t\t:class=\"{ 'cn-notes-card__note--reply': row.isReply }\">\n\t\t\t\t\t\t<span class=\"cn-notes-card__initials\" aria-hidden=\"true\">{{ initialsOf(getNoteAuthorName(row.note)) }}</span>\n\t\t\t\t\t\t<div class=\"cn-notes-card__note-header\">\n\t\t\t\t\t\t\t<CnUserActionMenu\n\t\t\t\t\t\t\t\tv-if=\"!isCurrentUser(row.note)\"\n\t\t\t\t\t\t\t\t:userId=\"getNoteAuthorId(row.note)\"\n\t\t\t\t\t\t\t\t:displayName=\"getNoteAuthorName(row.note)\">\n\t\t\t\t\t\t\t\t<strong class=\"cn-notes-card__author\">{{ getNoteAuthorName(row.note) }}</strong>\n\t\t\t\t\t\t\t</CnUserActionMenu>\n\t\t\t\t\t\t\t<strong v-else class=\"cn-notes-card__author cn-notes-card__author--self\">\n\t\t\t\t\t\t\t\t{{ getNoteAuthorName(row.note) }}\n\t\t\t\t\t\t\t</strong>\n\t\t\t\t\t\t\t<span class=\"cn-notes-card__time\">{{ formatDate(row.note.creationDateTime || row.note.created || row.note.createdAt) }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"visibilityShown\" class=\"cn-notes-card__visibility\">\n\t\t\t\t\t\t\t<CnVisibilityChip :visibility=\"row.note.visibility\" />\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tv-if=\"visibilityToggleShown\"\n\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-notes-card-visibility-toggle\"\n\t\t\t\t\t\t\t\t@click=\"toggleVisibility(row.note)\">\n\t\t\t\t\t\t\t\t{{ noteVisibility(row.note) === 'public' ? makeInternalLabel : makePublicLabel }}\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p v-if=\"row.quote\" class=\"cn-notes-card__quote\" data-testid=\"cn-notes-card-quote\">\n\t\t\t\t\t\t\t{{ row.quote }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p class=\"cn-notes-card__body\">\n\t\t\t\t\t\t\t<CnNoteBody :message=\"row.note.message || row.note.content || ''\" :record=\"isFileSource || isSourceMode ? null : record\" />\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canReply\"\n\t\t\t\t\t\t\tclass=\"cn-notes-card__reply-btn\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t:aria-label=\"replyAria(row.note)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-notes-card-reply\"\n\t\t\t\t\t\t\t@click=\"replyTo = row.note\">\n\t\t\t\t\t\t\t{{ replyLabel }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canDeleteNote(row.note)\"\n\t\t\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\t\t\tclass=\"cn-notes-card__delete-btn\"\n\t\t\t\t\t\t\t:aria-label=\"deleteLabel\"\n\t\t\t\t\t\t\t@click=\"confirmDelete(row.note)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Delete :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Footer: \"Show all\" link -->\n\t\t<template v-if=\"allNotes.length > maxDisplay\" #footer>\n\t\t\t<button\n\t\t\t\tclass=\"cn-notes-card__show-all\"\n\t\t\t\t@click=\"$emit('show-all')\">\n\t\t\t\t{{ showAllLabel }} ({{ allNotes.length }})\n\t\t\t</button>\n\t\t</template>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport CommentTextOutline from 'vue-material-design-icons/CommentTextOutline.vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport NotePlusOutline from 'vue-material-design-icons/NotePlusOutline.vue'\nimport Send from 'vue-material-design-icons/Send.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport CnNoteBody from '../CnNoteBody/CnNoteBody.vue'\nimport CnNoteComposer from '../CnNoteComposer/CnNoteComposer.vue'\nimport CnUserActionMenu from '../CnUserActionMenu/CnUserActionMenu.vue'\nimport CnVisibilityChip from '../CnVisibilityChip/CnVisibilityChip.vue'\nimport { useFileComments } from '../../composables/useFileComments.js'\nimport { normalizeLook } from '../../composables/useLook.js'\nimport { formatBoardDateTime } from '../../utils/fillTemplate.js'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { initialsOf } from '../../utils/initials.js'\nimport { leafSourceUrl } from '../../utils/leafSourceUrl.js'\nimport { extractMentionedGroupIds, extractMentionedIds } from '../../utils/mentions.js'\nimport { quoteFor, supportsReplies, threadNotes, threadRootId } from '../../utils/noteThreads.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnNotesCard — Inline notes widget for detail pages.\n *\n * Shows up to 5 recent notes with add/delete functionality.\n * Integrates CnUserActionMenu on author names for quick communication.\n *\n * Basic usage\n * ```vue\n * <CnNotesCard\n * register-id=\"uuid-register\"\n * schema-id=\"uuid-schema\"\n * object-id=\"uuid-object\" />\n * ```\n *\n * With sidebar sync\n * ```vue\n * <CnNotesCard\n * register-id=\"reg\"\n * schema-id=\"schema\"\n * object-id=\"obj\"\n * @note-added=\"refreshNotes\"\n * @note-deleted=\"refreshNotes\"\n * @show-all=\"openSidebarNotesTab\" />\n * ```\n *\n * @event note-added Emitted after a new note is successfully persisted. Payload: the created note object.\n * @event note-deleted Emitted after a note is successfully deleted. Payload: the deleted note ID.\n * @event visibility-changed Emitted after a note's visibility was changed. Payload: `{ id, visibility }`.\n * @event mention Emitted after a note that mentions someone was added. Payload: `{ objectId, register, schema, noteId, mentionedUserIds }`, plus `mentionedGroupIds` when a group (`@\"group/<gid>\"`) is mentioned. nc-vue notifies nobody; the listener does.\n * @event show-all Emitted when the user clicks the \"Show all\" button — parents typically open a full notes sidebar tab.\n */\n/**\n * The server's own sentence on a refused note write, '' when it gave none.\n *\n * @param {Response} response The refused response.\n * @return {Promise<string>} The message.\n */\nasync function refusalMessage(response) {\n\ttry {\n\t\tconst data = await response.json()\n\t\tconst message = serverErrorMessage({ message: '-', response: { data } })\n\t\treturn message === '-' ? '' : message\n\t} catch {\n\t\treturn ''\n\t}\n}\n\nexport default {\n\tname: 'CnNotesCard',\n\n\tcomponents: {\n\t\tCnDetailCard,\n\t\tCnNoteBody,\n\t\tCnNoteComposer,\n\t\tCnUserActionMenu,\n\t\tCnVisibilityChip,\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcLoadingIcon,\n\t\tNotePlusOutline,\n\t\tSend,\n\t\tDelete,\n\t},\n\n\tinject: {\n\t\tcnLook: { default: 'nextcloud' },\n\t},\n\n\tprops: {\n\t\t/** OpenRegister register ID */\n\t\tregisterId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema ID */\n\t\tschemaId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Object UUID */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Show the notes of a plain Nextcloud file instead of an OpenRegister\n\t\t * object: the file's id. Used when no `objectId` is given; the notes\n\t\t * are the file's comments (`/remote.php/dav/comments/files/{fileId}`),\n\t\t * the same ones the Files sidebar shows.\n\t\t */\n\t\tfileId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Base API URL for OpenRegister */\n\t\tapiBase: {\n\t\t\ttype: String,\n\t\t\tdefault: '/apps/openregister/api',\n\t\t},\n\n\t\t/**\n\t\t * Read the notes of something that is not an OpenRegister object:\n\t\t * `{ kind: 'flow-task', id }` reads `${apiBase}/flow-tasks/{id}/notes`.\n\t\t * `id` may be left out or written `@objectId` for `objectId`.\n\t\t *\n\t\t * @type {{kind: string, id?: (string|number)}|null}\n\t\t */\n\t\tsource: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * A notes URL that replaces the object's own: the list and the add go\n\t\t * to it, a delete to `{endpoint}/{noteId}`. `{id}` is filled with the\n\t\t * source's id or `objectId`.\n\t\t */\n\t\tendpoint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Maximum number of notes to display */\n\t\tmaxDisplay: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5,\n\t\t},\n\n\t\t/** Whether the card is collapsible */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Render the notes body without the surrounding CnDetailCard.\n\t\t *\n\t\t * Set when a surface already supplies the card and the title, such as a\n\t\t * tab panel whose open tab names the panel. Leaving the card on there\n\t\t * nests a card inside a card and shows the label twice.\n\t\t */\n\t\tchromeless: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Where the add form lives: `inline` (default) keeps it open above the\n\t\t * notes; `button` puts it behind an \"Add note\" button in the card's\n\t\t * header (DqTaak \"Notities\"), and closes it again once the note is\n\t\t * saved. A reply opens it either way. Without the card's header\n\t\t * (`chromeless`) the form stays inline.\n\t\t *\n\t\t * @spec openspec/changes/notes-card-composer-button/specs/notes-card-composer-button/spec.md#requirement-a-notes-card-can-keep-its-composer-behind-a-header-button\n\t\t */\n\t\tcomposer: {\n\t\t\ttype: String,\n\t\t\tdefault: 'inline',\n\t\t\tvalidator: (v) => ['inline', 'button'].includes(v),\n\t\t},\n\n\t\t/**\n\t\t * Show a chip on every note reading internal or public. A note without a\n\t\t * value reads as internal. Off by default, so a host that passes nothing\n\t\t * renders the card as before. Not used for a file source (file comments\n\t\t * carry no flag).\n\t\t */\n\t\tshowVisibility: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the caller may set visibility on this object: the answer the\n\t\t * server gives for `update` on it. The host passes it; the card never\n\t\t * infers it from the current user. When true the card offers the\n\t\t * public switch in the add-note form and a toggle on each note.\n\t\t */\n\t\tcanSetVisibility: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t// --- Pre-translated labels ---\n\t\t/** Card header title. */\n\t\ttitleLabel: { type: String, default: () => t('nextcloud-vue', 'Notes') },\n\t\t/** Label for the submit button that creates a new note. */\n\t\taddNoteLabel: { type: String, default: () => t('nextcloud-vue', 'Add note') },\n\t\t/** Placeholder shown inside the new-note textarea before any input. */\n\t\taddNotePlaceholder: { type: String, default: () => t('nextcloud-vue', 'Write a note…') },\n\t\t/** Empty-state text shown when the object has zero notes. */\n\t\tnoNotesLabel: { type: String, default: () => t('nextcloud-vue', 'No notes yet') },\n\t\t/** Label for the \"Show all\" button rendered when the note list is truncated. */\n\t\tshowAllLabel: { type: String, default: () => t('nextcloud-vue', 'Show all') },\n\t\t/** Text shown instead of the notes when Nextcloud refuses a file's comments (no access). */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'Notes are not available for this file') },\n\t\t/** Label of the add-note switch that makes the note public. */\n\t\tpublicSwitchLabel: { type: String, default: () => t('nextcloud-vue', 'Public (visible to the customer)') },\n\t\t/** Label of the per-note action that makes an internal note public. */\n\t\tmakePublicLabel: { type: String, default: () => t('nextcloud-vue', 'Make public') },\n\t\t/** Label of the per-note action that makes a public note internal. */\n\t\tmakeInternalLabel: { type: String, default: () => t('nextcloud-vue', 'Make internal') },\n\t\t/** Label of the Reply button (shown only when the backend supports replies). */\n\t\treplyLabel: { type: String, default: () => t('nextcloud-vue', 'Reply') },\n\t\t/** Aria label for the per-note delete icon button. */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete note') },\n\t\t/** Text shown when a `source` or `endpoint` read failed. */\n\t\tfailedLabel: { type: String, default: () => t('nextcloud-vue', 'The notes could not be loaded') },\n\t},\n\n\temits: ['mention', 'note-added', 'note-deleted', 'show-all', 'visibility-changed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tCommentTextOutline: markRaw(CommentTextOutline),\n\t\t\tallNotes: [],\n\t\t\tloading: false,\n\t\t\tnewNoteText: '',\n\t\t\t/** Whether the add form is open while `composer` is `button`. */\n\t\t\tcomposerOpen: false,\n\t\t\t/** Visibility the next note is written with (only sent when the caller may set it). */\n\t\t\tnewNoteVisibility: 'internal',\n\t\t\tnoteSaving: false,\n\t\t\tdeleteConfirmId: null,\n\t\t\t/** The file source answered 403 or 404: no notes and no add field. */\n\t\t\tunavailable: false,\n\t\t\t/** A `source` or `endpoint` read failed: said, rather than shown as no notes. */\n\t\t\tfailed: false,\n\t\t\t/** The note a reply is being written to, or null. */\n\t\t\treplyTo: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {boolean} Whether the add form sits behind the header's button. */\n\t\tcomposerBehindButton() {\n\t\t\treturn this.composer === 'button' && !this.chromeless && !this.unavailable\n\t\t},\n\n\t\t/** @return {boolean} Whether the add form shows. */\n\t\tcomposerShown() {\n\t\t\treturn !this.composerBehindButton || this.composerOpen || Boolean(this.replyTo)\n\t\t},\n\n\t\t/** Chips are shown: the host asked for them (or lets the caller set visibility) and the notes are object notes. */\n\t\tvisibilityShown() {\n\t\t\treturn (this.showVisibility || this.canSetVisibility) && !this.isFileSource\n\t\t},\n\n\t\t/** The switch and the per-note toggle are offered: only when the host says the caller may set it. */\n\t\tvisibilityToggleShown() {\n\t\t\treturn this.canSetVisibility && !this.isFileSource\n\t\t},\n\n\t\t/**\n\t\t * The notes URL a `source` or `endpoint` names, '' while its record id\n\t\t * is unknown, or null when the card reads an object.\n\t\t *\n\t\t * @return {string|null}\n\t\t * @spec openspec/changes/leaf-cards-read-a-source/specs/leaf-cards-read-a-source/spec.md#requirement-a-leaf-card-reads-a-source-or-an-endpoint\n\t\t */\n\t\tsourceUrl() {\n\t\t\treturn leafSourceUrl({ source: this.source, endpoint: this.endpoint, apiBase: this.apiBase, objectId: this.objectId }, 'notes')\n\t\t},\n\n\t\t/** The notes come from a `source` or `endpoint`, not from an object. */\n\t\tisSourceMode() {\n\t\t\treturn this.sourceUrl !== null\n\t\t},\n\n\t\t/** @return {string} The notes URL the list, add and delete use. */\n\t\tnotesUrl() {\n\t\t\tif (this.isSourceMode) {\n\t\t\t\treturn this.sourceUrl\n\t\t\t}\n\t\t\treturn `${this.apiBase}/objects/${this.registerId}/${this.schemaId}/${this.objectId}/notes`\n\t\t},\n\n\t\t/** The file source applies: a file id and no object. */\n\t\tisFileSource() {\n\t\t\treturn this.fileId !== null && this.fileId !== undefined && this.fileId !== '' && !this.objectId\n\t\t},\n\n\t\t/** @return {{apiBase: string, register: string, schema: string, objectId: string}} Where this record's files live, for pasted images. */\n\t\trecord() {\n\t\t\treturn { apiBase: this.apiBase, register: this.registerId, schema: this.schemaId, objectId: this.objectId }\n\t\t},\n\n\t\t/** @return {boolean} Whether the backend supports replies: its notes carry a `parentId` key. Not for a file's comments. */\n\t\tcanReply() {\n\t\t\treturn !this.isFileSource && supportsReplies(this.allNotes)\n\t\t},\n\n\t\t/** @return {Array<{note: object, replies: object[]}>} The shown notes as threads. */\n\t\tthreads() {\n\t\t\treturn threadNotes(this.displayedNotes)\n\t\t},\n\n\t\t/** @return {string} The line above the form while replying. */\n\t\treplyingLabel() {\n\t\t\treturn this.replyTo ? t('nextcloud-vue', 'Replying to {author}', { author: this.getNoteAuthorName(this.replyTo) }) : ''\n\t\t},\n\n\t\tdisplayedNotes() {\n\t\t\t// Reverse chronological, limited to maxDisplay\n\t\t\tconst sorted = [...this.allNotes].sort((a, b) => {\n\t\t\t\tconst dateA = new Date(a.creationDateTime || a.created || a.createdAt || 0)\n\t\t\t\tconst dateB = new Date(b.creationDateTime || b.created || b.createdAt || 0)\n\t\t\t\treturn dateB - dateA\n\t\t\t})\n\t\t\treturn sorted.slice(0, this.maxDisplay)\n\t\t},\n\t},\n\n\twatch: {\n\t\tfileId: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tif (this.isFileSource) {\n\t\t\t\t\tthis.fetchNotes()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(newId) {\n\t\t\t\tif (newId && this.registerId && this.schemaId && !this.isSourceMode) {\n\t\t\t\t\tthis.fetchNotes()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tsourceUrl: {\n\t\t\timmediate: true,\n\t\t\thandler(url) {\n\t\t\t\tif (typeof url === 'string' && url !== '') {\n\t\t\t\t\tthis.fetchNotes()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A note's visibility; an entry with no value reads as internal.\n\t\t *\n\t\t * @param {object} note The note.\n\t\t * @return {'public'|'internal'} The visibility.\n\t\t */\n\t\tnoteVisibility(note) {\n\t\t\treturn note && note.visibility === 'public' ? 'public' : 'internal'\n\t\t},\n\n\t\t/**\n\t\t * The one place a note write goes out: creating a note and changing its\n\t\t * visibility both send through here, so the value is sent from one spot.\n\t\t *\n\t\t * @param {'POST'|'PATCH'} method The HTTP method.\n\t\t * @param {string} url The notes URL (with the note id for a change).\n\t\t * @param {object} body The JSON body.\n\t\t * @return {Promise<Response>} The response.\n\t\t */\n\t\twriteNote(method, url, body) {\n\t\t\treturn fetch(prefixUrl(url), { method, headers: buildHeaders(), body: JSON.stringify(body) })\n\t\t},\n\n\t\t/**\n\t\t * Flip a note between internal and public.\n\t\t *\n\t\t * @param {object} note The note.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync toggleVisibility(note) {\n\t\t\tif (!this.visibilityToggleShown) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = this.noteVisibility(note) === 'public' ? 'internal' : 'public'\n\t\t\ttry {\n\t\t\t\tconst url = `${this.notesUrl}/${note.id}`\n\t\t\t\tconst response = await this.writeNote('PATCH', url, { visibility: next })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.allNotes = this.allNotes.map((n) => (n.id === note.id ? { ...n, visibility: next } : n))\n\t\t\t\t\t/** @event visibility-changed Emitted after a note's visibility was changed. Payload: `{ id, visibility }`. */\n\t\t\t\t\tthis.$emit('visibility-changed', { id: note.id, visibility: next })\n\t\t\t\t} else {\n\t\t\t\t\tthis.showError('Failed to change visibility')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error('CnNotesCard: Failed to change visibility', err)\n\t\t\t\tthis.showError('Failed to change visibility')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The rows of one thread: the note, then its replies. A reply whose parent\n\t\t * is far up the list carries a one-line quote of it.\n\t\t *\n\t\t * @param {{note: object, replies: object[]}} thread The thread.\n\t\t * @return {Array<{note: object, isReply: boolean, quote: string}>} The rows.\n\t\t */\n\t\tthreadRows(thread) {\n\t\t\tconst flat = this.threads.flatMap((t2) => [t2.note, ...t2.replies])\n\t\t\treturn [\n\t\t\t\t{ note: thread.note, isReply: false, quote: '' },\n\t\t\t\t...thread.replies.map((reply) => ({ note: reply, isReply: true, quote: quoteFor(reply, flat) })),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note A top-level note.\n\t\t * @return {string} The name of its thread for assistive technology.\n\t\t */\n\t\tthreadLabel(note) {\n\t\t\treturn t('nextcloud-vue', 'Note by {author} and its replies', { author: this.getNoteAuthorName(note) })\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note The note a Reply button answers.\n\t\t * @return {string} The button's accessible name, naming the author.\n\t\t */\n\t\treplyAria(note) {\n\t\t\treturn t('nextcloud-vue', 'Reply to {author}', { author: this.getNoteAuthorName(note) })\n\t\t},\n\n\t\t/**\n\t\t * Tell the host a saved note mentions someone. The payload keeps the\n\t\t * user ids and adds the group ids only when a group is mentioned.\n\t\t *\n\t\t * @param {string} text The saved text.\n\t\t * @param {string|null} noteId The note's id.\n\t\t * @return {void}\n\t\t */\n\t\temitMentionEvent(text, noteId) {\n\t\t\tconst mentionedUserIds = extractMentionedIds(text)\n\t\t\tconst mentionedGroupIds = extractMentionedGroupIds(text)\n\t\t\tif (mentionedUserIds.length === 0 && mentionedGroupIds.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('mention', {\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tregister: this.registerId,\n\t\t\t\tschema: this.schemaId,\n\t\t\t\tnoteId,\n\t\t\t\tmentionedUserIds,\n\t\t\t\t...(mentionedGroupIds.length > 0 ? { mentionedGroupIds } : {}),\n\t\t\t})\n\t\t},\n\n\t\tgetNoteAuthorId(note) {\n\t\t\treturn note.actorId || note.author || ''\n\t\t},\n\n\t\tinitialsOf,\n\n\t\tgetNoteAuthorName(note) {\n\t\t\treturn note.actorDisplayName || note.author || 'Unknown'\n\t\t},\n\n\t\tisCurrentUser(note) {\n\t\t\tif (note.isCurrentUser === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst authorId = this.getNoteAuthorId(note)\n\t\t\tconst currentUser = typeof OC !== 'undefined' ? OC?.currentUser : null\n\t\t\treturn authorId === currentUser\n\t\t},\n\n\t\tcanDeleteNote(note) {\n\t\t\treturn this.isCurrentUser(note)\n\t\t},\n\n\t\tfileComments() {\n\t\t\treturn useFileComments(this.fileId)\n\t\t},\n\n\t\tasync fetchNotes() {\n\t\t\tif (this.isFileSource) {\n\t\t\t\tthis.loading = true\n\t\t\t\tthis.unavailable = false\n\t\t\t\ttry {\n\t\t\t\t\tthis.allNotes = await this.fileComments().list()\n\t\t\t\t} catch (err) {\n\t\t\t\t\tthis.allNotes = []\n\t\t\t\t\tthis.unavailable = err && (err.status === 403 || err.status === 404)\n\t\t\t\t\tif (!this.unavailable) {\n\t\t\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\t\t\tconsole.error('CnNotesCard: Failed to fetch file comments', err)\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tthis.loading = false\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.isSourceMode ? this.notesUrl === '' : (!this.registerId || !this.schemaId || !this.objectId)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.notesUrl), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.allNotes = data.results || data || []\n\t\t\t\t} else if (this.isSourceMode) {\n\t\t\t\t\tthis.allNotes = []\n\t\t\t\t\tthis.failed = true\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis.failed = this.isSourceMode\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error('CnNotesCard: Failed to fetch notes', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync submitNote() {\n\t\t\tif (!this.newNoteText.trim() || this.noteSaving) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.noteSaving = true\n\t\t\tif (this.isFileSource) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.fileComments().add(this.newNoteText.trim())\n\t\t\t\t\tthis.composerOpen = false\n\t\t\t\t\tthis.newNoteText = ''\n\t\t\t\t\tawait this.fetchNotes()\n\t\t\t\t\tthis.$emit('note-added')\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\t\tconsole.error('CnNotesCard: Failed to add file comment', err)\n\t\t\t\t\tthis.showError('Failed to add note')\n\t\t\t\t} finally {\n\t\t\t\t\tthis.noteSaving = false\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst url = this.notesUrl\n\t\t\t\tconst body = { message: this.newNoteText.trim() }\n\t\t\t\tif (this.visibilityToggleShown) {\n\t\t\t\t\tbody.visibility = this.newNoteVisibility\n\t\t\t\t}\n\t\t\t\tif (this.replyTo) {\n\t\t\t\t\tbody.parentId = threadRootId(this.replyTo, this.allNotes)\n\t\t\t\t}\n\t\t\t\tconst response = await this.writeNote('POST', url, body)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tlet noteId = null\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst created = await response.json()\n\t\t\t\t\t\tnoteId = (created && (created.id || (created.results && created.results.id))) || null\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Body not JSON: the event still fires with noteId null.\n\t\t\t\t\t}\n\t\t\t\t\tthis.emitMentionEvent(body.message, noteId)\n\t\t\t\t\tthis.replyTo = null\n\t\t\t\t\tthis.composerOpen = false\n\t\t\t\t\tthis.newNoteText = ''\n\t\t\t\t\tthis.newNoteVisibility = 'internal'\n\t\t\t\t\tawait this.fetchNotes()\n\t\t\t\t\tthis.$emit('note-added')\n\t\t\t\t} else {\n\t\t\t\t\tthis.showError(await refusalMessage(response) || 'Failed to add note')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error('CnNotesCard: Failed to add note', err)\n\t\t\t\tthis.showError('Failed to add note')\n\t\t\t} finally {\n\t\t\t\tthis.noteSaving = false\n\t\t\t}\n\t\t},\n\n\t\tasync confirmDelete(note) {\n\t\t\t// Simple inline confirmation — delete directly\n\t\t\tif (this.isFileSource) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.fileComments().remove(note.id)\n\t\t\t\t\tthis.allNotes = this.allNotes.filter((n) => n.id !== note.id)\n\t\t\t\t\tthis.$emit('note-deleted')\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\t\tconsole.error('CnNotesCard: Failed to delete file comment', err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst url = `${this.notesUrl}/${note.id}`\n\t\t\t\tconst response = await fetch(prefixUrl(url), {\n\t\t\t\t\tmethod: 'DELETE',\n\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.allNotes = this.allNotes.filter((n) => n.id !== note.id)\n\t\t\t\t\tthis.$emit('note-deleted')\n\t\t\t\t} else {\n\t\t\t\t\tthis.showError(await refusalMessage(response) || 'Failed to delete note')\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error('CnNotesCard: Failed to delete note', err)\n\t\t\t}\n\t\t},\n\n\t\tformatDate(dateStr) {\n\t\t\tif (!dateStr) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// The board look writes a note's moment as the boards do: \"6 okt 11:10\", the year only outside this year.\n\t\t\tif (normalizeLook(this.cnLook) === 'board') {\n\t\t\t\treturn formatBoardDateTime(dateStr) || dateStr\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(dateStr).toLocaleString(userLocale(), {\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\thour: '2-digit',\n\t\t\t\t\tminute: '2-digit',\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn dateStr\n\t\t\t}\n\t\t},\n\n\t\tshowError(message) {\n\t\t\ttry {\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => {\n\t\t\t\t\tshowError(message)\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\t// eslint-disable-next-line no-console -- diagnostic for a failure this code already degrades from\n\t\t\t\tconsole.error(message)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-notes-card__add-form {\n\tmargin-bottom: 12px;\n}\n\n.cn-notes-card__textarea {\n\twidth: 100%;\n\tmargin-bottom: 8px;\n\tbox-sizing: border-box;\n}\n\n.cn-notes-card__replying {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin: 0 0 4px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-notes-card__note--reply {\n\tmargin-inline-start: 24px;\n}\n\n.cn-notes-card__quote {\n\tmargin: 0 0 2px;\n\tpadding-inline-start: 8px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-notes-card__empty {\n\ttext-align: center;\n\tpadding: 16px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-notes-card__list {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-notes-card__note {\n\tpadding: 10px 0;\n\tborder-bottom: 1px solid var(--color-border);\n\tposition: relative;\n}\n\n.cn-notes-card__note:last-child {\n\tborder-bottom: none;\n}\n\n.cn-notes-card__initials {\n\tdisplay: none;\n}\n\n.cn-notes-card__note-header {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: baseline;\n\tmargin-bottom: 4px;\n}\n\n.cn-notes-card__author {\n\tfont-size: 13px;\n}\n\n.cn-notes-card__author--self {\n\tcolor: var(--color-main-text);\n}\n\n.cn-notes-card__visibility {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin-bottom: 4px;\n}\n\n.cn-notes-card__time {\n\tfont-size: 11px;\n\tcolor: var(--color-text-maxcontrast);\n\tflex-shrink: 0;\n\tmargin-left: 8px;\n}\n\n.cn-notes-card__body {\n\tfont-size: 13px;\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n\tpadding-right: 32px;\n}\n\n/* The note's own class leads so the position outranks NcButton's\n `position: relative`, which loads later at the same weight and put the\n button in the flow under the note. */\n.cn-notes-card__note > .cn-notes-card__delete-btn {\n\tposition: absolute;\n\ttop: 8px;\n\tright: -4px;\n\topacity: 0;\n\ttransition: opacity 0.15s ease;\n}\n\n.cn-notes-card__note:hover > .cn-notes-card__delete-btn,\n.cn-notes-card__note:focus-within > .cn-notes-card__delete-btn {\n\topacity: 1;\n}\n\n.cn-notes-card__show-all {\n\tbackground: none;\n\tborder: none;\n\tcolor: var(--color-primary-element);\n\tfont-size: 13px;\n\tfont-weight: 500;\n\tcursor: pointer;\n\tpadding: 0;\n\twidth: 100%;\n\ttext-align: center;\n}\n\n.cn-notes-card__show-all:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_openBlock","_createElementBlock","_createTextVNode","_toDisplayString","_createVNode","_Fragment","_renderList","_normalizeClass","_createElementVNode"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnObjectCard.vue2.js';
|
|
|
2
2
|
import { render } from './CnObjectCard.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-6e1fe7c7";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -350,6 +350,17 @@ var script = {
|
|
|
350
350
|
return { text: part.text, tone }
|
|
351
351
|
},
|
|
352
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Whether the record layout names a `footerCell`, so an empty one
|
|
355
|
+
* keeps its place.
|
|
356
|
+
*
|
|
357
|
+
* @spec openspec/changes/card-empty-footer-cell-dash/specs/card-empty-footer-cell-dash/spec.md#requirement-an-empty-footer-cell-reads-as-a-dash
|
|
358
|
+
* @return {boolean}
|
|
359
|
+
*/
|
|
360
|
+
recordFootCellDeclared() {
|
|
361
|
+
return Boolean(this.recordLayout && this.recordLayout.footerCell)
|
|
362
|
+
},
|
|
363
|
+
|
|
353
364
|
/**
|
|
354
365
|
* The footer's `footerCell` part, read as a meta part is (through the
|
|
355
366
|
* page column it names), or null while it is empty.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnObjectCard.vue2.js","sources":["../../../../src/components/CnObjectCard/CnObjectCard.vue"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-object-card\"\n\t\t:class=\"[{ 'cn-object-card--selected': selected, 'cn-object-card--board': isBoardLook }, accentVariant && ['cn-object-card--accent', `cn-object-card--accent-${accentVariant}`]]\"\n\t\t@mousedown=\"onCardMouseDown\"\n\t\t@click=\"onCardClick($event)\"\n\t\t@auxclick=\"onCardAuxClick($event)\">\n\t\t<!-- Selection checkbox (a record card draws it in its head row) -->\n\t\t<div v-if=\"selectable && !recordLayout\"\n\t\t\tclass=\"cn-object-card__checkbox\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t</div>\n\n\t\t<!-- Board look, record layout (`layout`): head pill and number, title,\n\t\t meta line, then a footer with a pill and a date. -->\n\t\t<div v-if=\"recordLayout\" class=\"cn-object-card__content cn-object-card__record\" data-testid=\"cn-object-card-record\">\n\t\t\t<div class=\"cn-object-card__record-head\">\n\t\t\t\t<div v-if=\"selectable\"\n\t\t\t\t\tclass=\"cn-object-card__checkbox\"\n\t\t\t\t\t@click.stop\n\t\t\t\t\t@auxclick.stop>\n\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t\t\t</div>\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"recordHeadPill\"\n\t\t\t\t\tclass=\"cn-object-card__record-pill\"\n\t\t\t\t\t:label=\"recordHeadPill.label\"\n\t\t\t\t\t:variant=\"recordHeadPill.variant\"\n\t\t\t\t\tdata-testid=\"cn-object-card-head-pill\">\n\t\t\t\t\t<template v-if=\"recordHeadPill.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"recordHeadPill.icon\" :size=\"14\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnStatusBadge>\n\t\t\t\t<span v-if=\"recordNumber\" class=\"cn-object-card__record-number\" data-testid=\"cn-object-card-number\">{{ recordNumber }}</span>\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"$slots.actions\"\n\t\t\t\t\tclass=\"cn-object-card__menu\"\n\t\t\t\t\t@click.stop\n\t\t\t\t\t@auxclick.stop>\n\t\t\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<h3 class=\"cn-object-card__title\">\n\t\t\t\t<CnLockIndicator :object=\"object\" :size=\"16\" />\n\t\t\t\t{{ recordTitle }}\n\t\t\t</h3>\n\t\t\t<!-- A part whose field names a page column with a widget draws through\n\t\t\t it, as its table cell does; the rest are text. -->\n\t\t\t<p v-if=\"recordMetaParts.length > 0\" class=\"cn-object-card__record-meta\" data-testid=\"cn-object-card-meta\">\n\t\t\t\t<template v-for=\"(part, index) in recordMetaParts\" :key=\"part.field\">\n\t\t\t\t\t<span v-if=\"index > 0\" aria-hidden=\"true\"> · </span>\n\t\t\t\t\t<CnCellRenderer\n\t\t\t\t\t\tv-if=\"part.column && part.column.widget\"\n\t\t\t\t\t\t:value=\"part.value\"\n\t\t\t\t\t\t:widget=\"part.column.widget\"\n\t\t\t\t\t\t:widgetProps=\"part.column.widgetProps || undefined\"\n\t\t\t\t\t\t:formatter=\"part.column.formatter || null\"\n\t\t\t\t\t\t:formatterOptions=\"part.column.formatterOptions || null\"\n\t\t\t\t\t\t:row=\"object\" />\n\t\t\t\t\t<span v-else>{{ part.text }}</span>\n\t\t\t\t</template>\n\t\t\t</p>\n\t\t\t<p v-if=\"recordNote\"\n\t\t\t\tclass=\"cn-object-card__record-note\"\n\t\t\t\t:class=\"recordNote.tone ? 'cn-object-card__record-note--' + recordNote.tone : ''\"\n\t\t\t\tdata-testid=\"cn-object-card-note\">\n\t\t\t\t{{ recordNote.text }}\n\t\t\t</p>\n\t\t\t<p v-if=\"recordDescription\" class=\"cn-object-card__record-description\" data-testid=\"cn-object-card-description\">\n\t\t\t\t{{ recordDescription }}\n\t\t\t</p>\n\t\t\t<div v-if=\"recordChips.length > 0\" class=\"cn-object-card__record-chips\" data-testid=\"cn-object-card-chips\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-for=\"chip in recordChips\"\n\t\t\t\t\t:key=\"chip.field\"\n\t\t\t\t\tclass=\"cn-object-card__record-pill\"\n\t\t\t\t\t:label=\"chip.label\"\n\t\t\t\t\t:variant=\"chip.variant\">\n\t\t\t\t\t<template v-if=\"chip.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"chip.icon\" :size=\"14\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnStatusBadge>\n\t\t\t</div>\n\t\t\t<div v-if=\"$slots.badges\" class=\"cn-object-card__badges\">\n\t\t\t\t<slot name=\"badges\" :object=\"object\" />\n\t\t\t</div>\n\t\t\t<div v-if=\"recordFootPill || recordFootCell || recordDate\" class=\"cn-object-card__record-foot\" data-testid=\"cn-object-card-foot\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"recordFootPill\"\n\t\t\t\t\tclass=\"cn-object-card__record-pill\"\n\t\t\t\t\t:label=\"recordFootPill.label\"\n\t\t\t\t\t:variant=\"recordFootPill.variant\"\n\t\t\t\t\tdata-testid=\"cn-object-card-foot-pill\">\n\t\t\t\t\t<template v-if=\"recordFootPill.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"recordFootPill.icon\" :size=\"14\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnStatusBadge>\n\t\t\t\t<span v-if=\"recordFootCell\" class=\"cn-object-card__record-foot-cell\" data-testid=\"cn-object-card-foot-cell\">\n\t\t\t\t\t<CnCellRenderer\n\t\t\t\t\t\tv-if=\"recordFootCell.column && recordFootCell.column.widget\"\n\t\t\t\t\t\t:value=\"recordFootCell.value\"\n\t\t\t\t\t\t:widget=\"recordFootCell.column.widget\"\n\t\t\t\t\t\t:widgetProps=\"recordFootCell.column.widgetProps || undefined\"\n\t\t\t\t\t\t:formatter=\"recordFootCell.column.formatter || null\"\n\t\t\t\t\t\t:formatterOptions=\"recordFootCell.column.formatterOptions || null\"\n\t\t\t\t\t\t:row=\"object\" />\n\t\t\t\t\t<template v-else>{{ recordFootCell.text }}</template>\n\t\t\t\t</span>\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"recordDate\"\n\t\t\t\t\tclass=\"cn-object-card__record-date\"\n\t\t\t\t\t:class=\"[recordDateTone ? 'cn-object-card__record-date--' + recordDateTone : '']\"\n\t\t\t\t\tdata-testid=\"cn-object-card-date\">{{ recordDate }}</span>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Card content -->\n\t\t<div v-else class=\"cn-object-card__content\">\n\t\t\t<!-- Header: image + title -->\n\t\t\t<div class=\"cn-object-card__header\">\n\t\t\t\t<!-- Board look: the leading element, initials in a circle or an icon on a tint. -->\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"isBoardLook && leadingKind\"\n\t\t\t\t\tclass=\"cn-object-card__leading\"\n\t\t\t\t\t:class=\"`cn-object-card__leading--${leadingKind}`\"\n\t\t\t\t\tdata-testid=\"cn-object-card-leading\"\n\t\t\t\t\taria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"leadingKind === 'initials'\">{{ leading.initials }}</template>\n\t\t\t\t\t<CnIcon v-else :name=\"leading.icon\" :size=\"20\" />\n\t\t\t\t</span>\n\t\t\t\t<img\n\t\t\t\t\tv-if=\"imageUrl\"\n\t\t\t\t\t:src=\"imageUrl\"\n\t\t\t\t\t:alt=\"title\"\n\t\t\t\t\tclass=\"cn-object-card__image\">\n\n\t\t\t\t<div class=\"cn-object-card__title-area\">\n\t\t\t\t\t<h3 class=\"cn-object-card__title\">\n\t\t\t\t\t\t<!-- Beside the title, not in the badges row: the badges\n\t\t\t\t\t\t slot is the consumer's, and a lock is the library's\n\t\t\t\t\t\t to report. A card whose consumer passes no badges\n\t\t\t\t\t\t would otherwise show no padlock at all. -->\n\t\t\t\t\t\t<CnLockIndicator :object=\"object\" :size=\"16\" />\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"accentVariant && accent.icon\"\n\t\t\t\t\t\t\tclass=\"cn-object-card__accent-icon\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-card-accent-icon\"\n\t\t\t\t\t\t\t:role=\"accent.label ? 'img' : null\"\n\t\t\t\t\t\t\t:aria-label=\"accent.label || null\"\n\t\t\t\t\t\t\t:aria-hidden=\"accent.label ? null : 'true'\"\n\t\t\t\t\t\t\t:title=\"accent.label || null\">\n\t\t\t\t\t\t\t<CnIcon :name=\"accent.icon\" :size=\"16\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t{{ title }}\n\t\t\t\t\t</h3>\n\t\t\t\t\t<p v-if=\"description\" class=\"cn-object-card__description\">\n\t\t\t\t\t\t{{ truncatedDescription }}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<!-- Board look, end of the head: the status pill, or else the row menu. -->\n\t\t\t\t<template v-if=\"isBoardLook\">\n\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\tv-if=\"statusPill\"\n\t\t\t\t\t\tclass=\"cn-object-card__status\"\n\t\t\t\t\t\t:label=\"statusPill.label\"\n\t\t\t\t\t\t:variant=\"statusPill.variant\"\n\t\t\t\t\t\tdata-testid=\"cn-object-card-status\" />\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-else-if=\"$slots.actions\"\n\t\t\t\t\t\tclass=\"cn-object-card__menu\"\n\t\t\t\t\t\t@click.stop\n\t\t\t\t\t\t@auxclick.stop>\n\t\t\t\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t</div>\n\n\t\t\t<!-- Badges slot -->\n\t\t\t<div v-if=\"$slots.badges\" class=\"cn-object-card__badges\">\n\t\t\t\t<slot name=\"badges\" :object=\"object\" />\n\t\t\t</div>\n\n\t\t\t<!-- Metadata: visible properties as label:value pairs -->\n\t\t\t<div v-if=\"metadataFields.length > 0\" class=\"cn-object-card__metadata\" :class=\"{ 'cn-object-card__metadata--facts': isBoardLook }\">\n\t\t\t\t<slot name=\"metadata\" :object=\"object\" :fields=\"metadataFields\">\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-for=\"field in metadataFields\"\n\t\t\t\t\t\t:key=\"field.key\"\n\t\t\t\t\t\tclass=\"cn-object-card__meta-item\">\n\t\t\t\t\t\t<span class=\"cn-object-card__meta-label\">{{ field.label }}</span>\n\t\t\t\t\t\t<CnCellRenderer\n\t\t\t\t\t\t\t:value=\"field.value\"\n\t\t\t\t\t\t\t:property=\"field.property\"\n\t\t\t\t\t\t\t:formatter=\"field.column && field.column.formatter || null\"\n\t\t\t\t\t\t\t:formatterOptions=\"field.column && field.column.formatterOptions || null\"\n\t\t\t\t\t\t\t:widget=\"field.column && field.column.widget || null\"\n\t\t\t\t\t\t\t:widgetProps=\"field.column && field.column.widgetProps || undefined\"\n\t\t\t\t\t\t\t:row=\"object\"\n\t\t\t\t\t\t\t:truncate=\"60\" />\n\t\t\t\t\t</div>\n\t\t\t\t</slot>\n\t\t\t</div>\n\n\t\t\t<!-- Board look: one footer action, with a muted meta text at the start. -->\n\t\t\t<div\n\t\t\t\tv-if=\"isBoardLook && footerAction\"\n\t\t\t\tclass=\"cn-object-card__footer\"\n\t\t\t\tdata-testid=\"cn-object-card-footer\"\n\t\t\t\t@click.stop\n\t\t\t\t@auxclick.stop>\n\t\t\t\t<span v-if=\"footerAction.meta\" class=\"cn-object-card__footer-meta\">{{ footerAction.meta }}</span>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\tclass=\"cn-object-card__footer-action\"\n\t\t\t\t\tdata-testid=\"cn-object-card-footer-action\"\n\t\t\t\t\t:aria-label=\"footerAction.ariaLabel || `${footerAction.label} ${title}`\"\n\t\t\t\t\t@click=\"$emit('footer-action', object, footerAction)\">\n\t\t\t\t\t{{ footerAction.label }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Actions slot -->\n\t\t<div v-if=\"$slots.actions && !isBoardLook\"\n\t\t\tclass=\"cn-object-card__actions\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport { useClickDragGuard } from '../../composables/useClickDragGuard.js'\nimport { normalizeLook } from '../../composables/useLook.js'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { formatBoardDate } from '../../utils/boardDate.js'\nimport { resolveDateVariant } from '../../utils/dateVariant.js'\nimport { pillLook } from '../../utils/detailActionModel.js'\nimport { resolveDue } from '../../utils/dueText.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { resolveImageUrl } from '../../utils/resolveImageUrl.js'\nimport { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'\nimport { formatValue } from '../../utils/schema.js'\nimport { CnCellRenderer } from '../CnCellRenderer/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnLockIndicator } from '../CnLockIndicator/index.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\nconst ACCENT_VARIANTS = ['success', 'warning', 'error', 'info', 'primary']\n\n/**\n * CnObjectCard — Schema-configuration-driven card for object display.\n *\n * Uses `schema.configuration` to determine which fields map to the card title,\n * description, and image. Remaining visible properties are shown as metadata.\n *\n * ```vue\n * <CnObjectCard :object=\"publication\" :schema=\"pubSchema\">\n * <template #actions=\"{ object }\">\n * <NcActions><NcActionButton @click=\"edit(object)\">Edit</NcActionButton></NcActions>\n * </template>\n * </CnObjectCard>\n * ```\n */\nexport default {\n\tname: 'CnObjectCard',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tCnCellRenderer,\n\t\tCnIcon,\n\t\tCnLockIndicator,\n\t\tCnStatusBadge,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Consumer translation function, provided by CnAppRoot as\n\t\t * `cnTranslate: this.translate` (bound to the host app's id). Metadata\n\t\t * labels come from schema property titles, authored in English as the\n\t\t * canonical source; the visible label is resolved through this function\n\t\t * so it follows the user's language. Defaults to identity when used\n\t\t * standalone (no CnAppRoot ancestor).\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The look CnAppRoot provides; `board` draws the record card of the screens. */\n\t\tcnLook: { default: 'nextcloud' },\n\t\t/** The cell formatters CnAppRoot provides, for a layout part whose page column names one. */\n\t\tcnFormatters: { default: () => ({}) },\n\t},\n\n\tprops: {\n\t\t/** The object data */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema definition with properties and configuration */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether this card is selected */\n\t\tselected: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show selection checkbox */\n\t\tselectable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * When true, a body click on a SELECTABLE card emits `click`\n\t\t * (navigation) instead of toggling selection — selection then happens\n\t\t * via the checkbox only. The card counterpart of CnIndexPage's\n\t\t * `rowClickToView` (a table row click already navigates in that mode).\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tclickToView: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the status pill at the end of the head row, as a label\n\t\t * (`\"Open\"`) or `{ label, variant }` with a CnStatusBadge variant\n\t\t * (`success`, `warning`, `error`, `info`, `primary`, `default`).\n\t\t * Without it the head row ends in the row menu, when there is one.\n\t\t *\n\t\t * @type {(string|{label: string, variant?: string})}\n\t\t * @spec openspec/changes/screens-card-parity/specs/card-board-look/spec.md#requirement-a-record-card-has-a-head-facts-and-one-action\n\t\t */\n\t\tstatus: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the leading element of the head row. `{ initials }`\n\t\t * draws the initials in a 36px circle; `{ icon }` a schema icon in a\n\t\t * 36px rounded square on a tint.\n\t\t *\n\t\t * @type {{initials?: string, icon?: string}}\n\t\t */\n\t\tleading: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the card's one footer action. `{ label, meta?,\n\t\t * ariaLabel? }`; `meta` is the 13px muted text at the start of the\n\t\t * footer. Clicking emits `footer-action`.\n\t\t *\n\t\t * @type {{label: string, meta?: string, ariaLabel?: string}}\n\t\t */\n\t\tfooterAction: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * A status accent: a colored border at the start of the card and,\n\t\t * with `icon`, a colored icon before the title. `variant` is one of\n\t\t * `success`, `warning`, `error`, `info` or `primary`; `icon` is a\n\t\t * name registered with CnIcon; `label` names the status for screen\n\t\t * readers and as the icon's tooltip.\n\t\t *\n\t\t * @type {{variant: string, icon?: string, label?: string}}\n\t\t */\n\t\taccent: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the record layout (manifest key `config.cardLayout`).\n\t\t * Every part names a field of the object (a dot path) and is left out\n\t\t * while that field is empty:\n\t\t * `{ headPill, number, title, meta, footerPill, footerDate }`.\n\t\t * A pill is `{ field, colorMap?, labels?, variant? }`: `colorMap` maps a\n\t\t * value to a CnStatusBadge variant (ignoring case), `labels` a value to\n\t\t * the text shown. `meta` is a list of fields, joined with \" · \".\n\t\t * `footerDate` is `{ field, label?, overdueVariant? }`, drawn as\n\t\t * \"Termijn 5 okt\", in `overdueVariant`'s tone (`error`) once the date\n\t\t * has passed. `description` is a field (or `{ field, maxLength? }`, cut\n\t\t * at 140 characters by default) drawn under the meta line. `chips` is a\n\t\t * list of `{ field, formatter?, formatterOptions?, colorMap?, labels?,\n\t\t * variant? }`, each a pill whose text reads through the formatter.\n\t\t * `note` is `{ field, formatter?, formatterOptions?, tone? }`, a line\n\t\t * under the meta line in the `purple` or `teal` pill ink.\n\t\t * Without it the card keeps its head, facts and action.\n\t\t *\n\t\t * @type {{headPill?: object, number?: string, title?: string, meta?: Array<string>, description?: (string|{field: string, maxLength?: number}), chips?: Array<object>, note?: {field: string, formatter?: string, formatterOptions?: object, tone?: string}, footerPill?: object, footerDate?: {field: string, label?: string, overdueVariant?: string}}}\n\t\t * @spec openspec/changes/board-record-card-layout/specs/board-record-card-layout/spec.md#requirement-a-board-card-can-draw-the-record-layout-from-config\n\t\t */\n\t\tlayout: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The referenced records' colour and icon names, by field and id\n\t\t * (`{ [field]: { [id]: { color, icon } } }`, CnIndexPage reads them).\n\t\t * A record layout pill with `resolve: { colorField?, iconField? }` takes\n\t\t * its record's tone and icon from here.\n\t\t *\n\t\t * @type {object}\n\t\t * @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-card-pill-takes-its-tone-and-icon-from-the-referenced-record\n\t\t */\n\t\tpillLooks: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The property keys the facts list shows, in order (manifest key\n\t\t * `config.cardFields`). Without it the card shows the first\n\t\t * `maxMetadata` visible properties, as before.\n\t\t *\n\t\t * @type {Array<string>}\n\t\t */\n\t\tcardFields: {\n\t\t\ttype: Array,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The page's columns by key: a fact whose key names a column renders\n\t\t * through that column's label, formatter and widget, as the table does.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcardFieldColumns: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Maximum number of metadata fields to show */\n\t\tmaxMetadata: {\n\t\t\ttype: Number,\n\t\t\tdefault: 4,\n\t\t},\n\t},\n\n\temits: ['click', 'select', 'aux-click', 'footer-action'],\n\n\tsetup() {\n\t\t// Tell a deliberate card click apart from a text-selection drag.\n\t\treturn useClickDragGuard()\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the record card of the board look is drawn.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tisBoardLook() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/**\n\t\t * `initials`, `icon` or '' for the head row's leading element.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tleadingKind() {\n\t\t\tif (this.leading && typeof this.leading.initials === 'string' && this.leading.initials !== '') {\n\t\t\t\treturn 'initials'\n\t\t\t}\n\t\t\treturn this.leading && typeof this.leading.icon === 'string' && this.leading.icon !== '' ? 'icon' : ''\n\t\t},\n\n\t\t/**\n\t\t * The status as `{ label, variant }`, or null.\n\t\t *\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\tstatusPill() {\n\t\t\tif (typeof this.status === 'string' && this.status !== '') {\n\t\t\t\treturn { label: this.status, variant: 'default' }\n\t\t\t}\n\t\t\tif (this.status && typeof this.status.label === 'string' && this.status.label !== '') {\n\t\t\t\treturn { label: this.status.label, variant: this.status.variant || 'default' }\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The record layout when the board look draws it, else null.\n\t\t *\n\t\t * @return {?object}\n\t\t * @spec openspec/changes/board-record-card-layout/specs/board-record-card-layout/spec.md#requirement-a-board-card-can-draw-the-record-layout-from-config\n\t\t */\n\t\trecordLayout() {\n\t\t\treturn this.isBoardLook && this.layout && typeof this.layout === 'object' ? this.layout : null\n\t\t},\n\n\t\t/**\n\t\t * The record layout's head pill, or null.\n\t\t *\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\trecordHeadPill() {\n\t\t\treturn this.recordLayout ? this.layoutPill(this.recordLayout.headPill) : null\n\t\t},\n\n\t\t/**\n\t\t * The record layout's footer pill, or null.\n\t\t *\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\trecordFootPill() {\n\t\t\treturn this.recordLayout ? this.layoutPill(this.recordLayout.footerPill) : null\n\t\t},\n\n\t\t/**\n\t\t * The record number at the end of the head, or ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\trecordNumber() {\n\t\t\treturn this.recordLayout ? this.layoutText(this.recordLayout.number) : ''\n\t\t},\n\n\t\t/**\n\t\t * The title: the layout's `title` field, else the card's own title.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\trecordTitle() {\n\t\t\tconst text = this.recordLayout ? this.layoutText(this.recordLayout.title) : ''\n\t\t\treturn text !== '' ? text : this.title\n\t\t},\n\n\t\t/**\n\t\t * The meta line: the layout's `meta` fields that hold a value, joined.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\trecordMeta() {\n\t\t\treturn this.recordMetaParts.map((part) => part.text).join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * The meta line's parts that hold a value: each with its text and, when\n\t\t * its field names a page column, that column (whose widget draws it).\n\t\t *\n\t\t * @return {Array<{field: string, value: unknown, text: string, column: ?object}>}\n\t\t */\n\t\trecordMetaParts() {\n\t\t\tconst fields = this.recordLayout && Array.isArray(this.recordLayout.meta) ? this.recordLayout.meta : []\n\t\t\treturn fields\n\t\t\t\t.map((part) => this.metaPart(part))\n\t\t\t\t.filter((part) => part !== null && part.text !== '')\n\t\t},\n\n\t\t/**\n\t\t * The `note` line under the meta line, read as a meta part is, with\n\t\t * its tone (`purple`, `teal`), or null while it is empty.\n\t\t *\n\t\t * @return {?{text: string, tone: string}}\n\t\t * @spec openspec/changes/card-layout-note/specs/card-layout-note/spec.md#requirement-a-record-card-can-draw-a-toned-note-under-its-meta-line\n\t\t */\n\t\trecordNote() {\n\t\t\tconst def = this.recordLayout ? this.recordLayout.note : null\n\t\t\tconst part = def ? this.metaPart(def) : null\n\t\t\tif (!part || part.text === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst tone = ['purple', 'teal'].includes(def.tone) ? def.tone : ''\n\t\t\treturn { text: part.text, tone }\n\t\t},\n\n\t\t/**\n\t\t * The footer's `footerCell` part, read as a meta part is (through the\n\t\t * page column it names), or null while it is empty.\n\t\t *\n\t\t * @return {?{field: string, value: unknown, text: string, column: ?object}}\n\t\t */\n\t\trecordFootCell() {\n\t\t\tconst part = this.recordLayout ? this.metaPart(this.recordLayout.footerCell) : null\n\t\t\treturn part && part.text !== '' ? part : null\n\t\t},\n\n\t\t/**\n\t\t * The footer date with its label (\"Termijn 5 okt\"), or ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\trecordDate() {\n\t\t\tconst def = this.recordLayout ? this.recordLayout.footerDate : null\n\t\t\tif (!def || typeof def.field !== 'string') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst date = formatBoardDate(readPath(this.object, def.field))\n\t\t\tif (date === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof def.label === 'string' && def.label !== '' ? `${this.cnTranslate(def.label)} ${date}` : date\n\t\t},\n\n\t\t/**\n\t\t * The tone of the footer date: `overdueVariant` once the date has\n\t\t * passed, else ''.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/saved-view-overrides/specs/saved-views-ui/spec.md#requirement-a-board-card-can-draw-a-description-chips-and-an-overdue-date\n\t\t */\n\t\trecordDateTone() {\n\t\t\tconst def = this.recordLayout ? this.recordLayout.footerDate : null\n\t\t\tif (!def || typeof def.field !== 'string' || typeof def.overdueVariant !== 'string' || def.overdueVariant === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn this.dueVariant(readPath(this.object, def.field), {}) === 'error' ? def.overdueVariant : ''\n\t\t},\n\n\t\t/**\n\t\t * The description line, cut at `maxLength` characters (140 by\n\t\t * default) with an ellipsis, or ''.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/saved-view-overrides/specs/saved-views-ui/spec.md#requirement-a-board-card-can-draw-a-description-chips-and-an-overdue-date\n\t\t */\n\t\trecordDescription() {\n\t\t\tconst def = this.recordLayout ? this.recordLayout.description : null\n\t\t\tconst field = typeof def === 'string' ? def : (def && typeof def.field === 'string' ? def.field : '')\n\t\t\tconst text = this.layoutText(field).trim()\n\t\t\tconst max = def && typeof def === 'object' && Number.isInteger(def.maxLength) && def.maxLength > 0 ? def.maxLength : 140\n\t\t\treturn text.length > max ? `${text.slice(0, max).trimEnd()}…` : text\n\t\t},\n\n\t\t/**\n\t\t * The chips: one pill per `chips` entry whose field holds a value, its\n\t\t * text read through the entry's formatter (a status uuid as its name).\n\t\t *\n\t\t * @return {Array<{field: string, label: string, variant: string}>}\n\t\t * @spec openspec/changes/saved-view-overrides/specs/saved-views-ui/spec.md#requirement-a-board-card-can-draw-a-description-chips-and-an-overdue-date\n\t\t */\n\t\trecordChips() {\n\t\t\tconst chips = this.recordLayout && Array.isArray(this.recordLayout.chips) ? this.recordLayout.chips : []\n\t\t\treturn chips\n\t\t\t\t.map((def) => (typeof def === 'string' ? { field: def } : def))\n\t\t\t\t.filter((def) => def && typeof def.field === 'string' && def.field !== '')\n\t\t\t\t.map((def) => {\n\t\t\t\t\tconst column = typeof def.formatter === 'string' ? { formatter: def.formatter, formatterOptions: def.formatterOptions } : undefined\n\t\t\t\t\tconst label = this.layoutText(def.field, column)\n\t\t\t\t\tif (label === '') {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\tconst raw = readPath(this.object, def.field)\n\t\t\t\t\tconst mapped = def.colorMap && typeof def.colorMap === 'object' ? def.colorMap[String(raw)] || def.colorMap[String(raw).toLowerCase()] : undefined\n\t\t\t\t\tconst labels = def.labels && typeof def.labels === 'object' ? def.labels : {}\n\t\t\t\t\tconst shown = typeof labels[String(raw)] === 'string' ? this.cnTranslate(labels[String(raw)]) : label\n\t\t\t\t\tconst variant = mapped || def.variant\n\t\t\t\t\treturn this.withLook({ field: def.field, label: shown, variant: isBadgeVariant(variant) ? variant : 'default' }, def)\n\t\t\t\t})\n\t\t\t\t.filter(Boolean)\n\t\t},\n\n\t\t/**\n\t\t * The accent variant when it is a known one, else ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\taccentVariant() {\n\t\t\tconst variant = this.accent?.variant\n\t\t\treturn ACCENT_VARIANTS.includes(variant) ? variant : ''\n\t\t},\n\n\t\tconfig() {\n\t\t\treturn this.schema?.configuration || {}\n\t\t},\n\n\t\ttitle() {\n\t\t\tconst field = this.config.objectNameField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.object.title || this.object.name || this.object.id || '—'\n\t\t},\n\n\t\tdescription() {\n\t\t\tconst field = this.config.objectDescriptionField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\ttruncatedDescription() {\n\t\t\tif (!this.description) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (this.description.length > 120) {\n\t\t\t\treturn this.description.substring(0, 120) + '...'\n\t\t\t}\n\t\t\treturn this.description\n\t\t},\n\n\t\timageUrl() {\n\t\t\tconst field = this.config.objectImageField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn resolveImageUrl(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/** Fields excluded from metadata (already shown as title/desc/image) */\n\t\tconfigFields() {\n\t\t\treturn [\n\t\t\t\tthis.config.objectNameField,\n\t\t\t\tthis.config.objectDescriptionField,\n\t\t\t\tthis.config.objectSummaryField,\n\t\t\t\tthis.config.objectImageField,\n\t\t\t].filter(Boolean)\n\t\t},\n\n\t\t/** Remaining visible properties for the metadata section */\n\t\tmetadataFields() {\n\t\t\tif (!this.schema?.properties) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\t// The page names the facts: those properties, in that order.\n\t\t\tif (Array.isArray(this.cardFields)) {\n\t\t\t\treturn this.cardFields\n\t\t\t\t\t.filter((key) => typeof key === 'string' && this.schema.properties[key] && !this.configFields.includes(key))\n\t\t\t\t\t.map((key) => this.metadataField(key, this.schema.properties[key]))\n\t\t\t}\n\n\t\t\treturn Object.entries(this.schema.properties)\n\t\t\t\t.filter(([key, prop]) => {\n\t\t\t\t\tif (this.configFields.includes(key)) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\tif (prop.visible === false) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\tif (prop.type === 'object') {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\tif (prop.format === 'markdown') {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\treturn true\n\t\t\t\t})\n\t\t\t\t.sort(([, a], [, b]) => {\n\t\t\t\t\tconst orderA = typeof a.order === 'number' ? a.order : Infinity\n\t\t\t\t\tconst orderB = typeof b.order === 'number' ? b.order : Infinity\n\t\t\t\t\treturn orderA - orderB\n\t\t\t\t})\n\t\t\t\t.slice(0, this.maxMetadata)\n\t\t\t\t.map(([key, prop]) => this.metadataField(key, prop))\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * One meta part: a field name reads through the page column it names;\n\t\t * `{ field, formatter?, formatterOptions? }` reads as plain text through\n\t\t * its own formatter, so a column's widget (a badge) stays in the table.\n\t\t *\n\t\t * @param {string|{field: string, formatter?: string, formatterOptions?: object}} part The part.\n\t\t * @return {?{field: string, value: unknown, text: string, column: ?object}} The part, or null when it names no field.\n\t\t * @spec openspec/changes/card-layout-part-formatter/specs/card-layout-part-formatter/spec.md#requirement-a-card-meta-part-can-name-its-own-formatter\n\t\t */\n\t\tmetaPart(part) {\n\t\t\tif (typeof part === 'string' && part !== '') {\n\t\t\t\treturn { field: part, value: readPath(this.object, part), text: this.layoutText(part), column: this.layoutColumn(part) }\n\t\t\t}\n\t\t\tif (!part || typeof part !== 'object' || typeof part.field !== 'string' || part.field === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst column = typeof part.formatter === 'string' ? { formatter: part.formatter, formatterOptions: part.formatterOptions } : null\n\t\t\treturn { field: part.field, value: readPath(this.object, part.field), text: this.layoutText(part.field, column), column }\n\t\t},\n\n\t\t/**\n\t\t * A field's value as text: a person or a record by its display name,\n\t\t * title or name, anything else as a string. '' for an empty value or\n\t\t * a field that is not named.\n\t\t *\n\t\t * @param {unknown} field A dot path into the object.\n\t\t * @param {?object} [own] The column to read through instead of the one the field names.\n\t\t * @return {string}\n\t\t */\n\t\tlayoutText(field, own) {\n\t\t\tif (typeof field !== 'string' || field === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst value = readPath(this.object, field)\n\t\t\tif (value === null || value === undefined || value === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// A part whose field names a page column with a formatter reads as\n\t\t\t// its table cell does (a case type uuid as its name).\n\t\t\tconst column = own === undefined ? this.layoutColumn(field) : own\n\t\t\tconst format = column && column.formatter && this.cnFormatters ? this.cnFormatters[column.formatter] : null\n\t\t\tif (typeof format === 'function') {\n\t\t\t\tconst formatted = format(value, this.object, this.schema?.properties?.[field], column.formatterOptions || undefined)\n\t\t\t\treturn formatted === null || formatted === undefined ? '' : String(formatted)\n\t\t\t}\n\t\t\tif (typeof value === 'object') {\n\t\t\t\tconst name = value.displayName || value.title || value.name\n\t\t\t\treturn typeof name === 'string' ? name : ''\n\t\t\t}\n\t\t\treturn String(value)\n\t\t},\n\n\t\t/**\n\t\t * The page column a layout part's field names, or null.\n\t\t *\n\t\t * @param {string} field The part's field.\n\t\t * @return {?object} The column.\n\t\t */\n\t\tlayoutColumn(field) {\n\t\t\treturn (this.cardFieldColumns && typeof field === 'string' && this.cardFieldColumns[field]) || null\n\t\t},\n\n\t\t/**\n\t\t * A pill that reads its date field through the due rules: `variantWhen`\n\t\t * (the first rule the days left match gives the tone), else `due`\n\t\t * (overdue reads as error, within `due.soonWithin` days as warning).\n\t\t * The label is `labels[variant]`, else `labels.overdue` / `labels.soon`,\n\t\t * else Overdue / Soon, through the host's translate. Any other date\n\t\t * draws no pill.\n\t\t *\n\t\t * @param {{field: string, due?: object, variantWhen?: Array, labels?: object}} def The pill.\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\tdatePill(def) {\n\t\t\tconst value = readPath(this.object, def.field)\n\t\t\tconst variant = Array.isArray(def.variantWhen)\n\t\t\t\t? this.dateRuleVariant(value, def.variantWhen)\n\t\t\t\t: this.dueVariant(value, def.due)\n\t\t\tif (variant === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst labels = def.labels && typeof def.labels === 'object' ? def.labels : {}\n\t\t\tconst state = variant === 'error' ? 'overdue' : (variant === 'warning' ? 'soon' : '')\n\t\t\tconst authored = labels[variant] || (state && labels[state])\n\t\t\tif (typeof authored === 'string' && authored !== '') {\n\t\t\t\treturn { label: this.cnTranslate(authored), variant }\n\t\t\t}\n\t\t\tif (state === 'overdue') {\n\t\t\t\treturn { label: t('nextcloud-vue', 'Overdue'), variant }\n\t\t\t}\n\t\t\tif (state === 'soon') {\n\t\t\t\treturn { label: t('nextcloud-vue', 'Soon'), variant }\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The variant of the first `variantWhen` rule a date matches, or ''.\n\t\t *\n\t\t * @param {unknown} value The date.\n\t\t * @param {Array} rules The rules.\n\t\t * @return {string} The variant, or ''.\n\t\t */\n\t\tdateRuleVariant(value, rules) {\n\t\t\tconst matched = resolveDateVariant(value, rules)\n\t\t\treturn matched === 'default' ? '' : matched\n\t\t},\n\n\t\t/**\n\t\t * The variant the due rules give a date: error when overdue, warning\n\t\t * within `soonWithin` days, else ''.\n\t\t *\n\t\t * @param {unknown} value The date.\n\t\t * @param {object} config The `due` config.\n\t\t * @return {string} The variant, or ''.\n\t\t */\n\t\tdueVariant(value, config) {\n\t\t\tconst due = resolveDue(value, config)\n\t\t\tif (due && due.tone === 'danger') {\n\t\t\t\treturn 'error'\n\t\t\t}\n\t\t\treturn due && due.soon ? 'warning' : ''\n\t\t},\n\n\t\t/**\n\t\t * A layout pill as `{ label, variant }`, or null while its field is\n\t\t * empty.\n\t\t *\n\t\t * @param {?{field: string, colorMap?: object, labels?: object, variant?: string}} def The pill.\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\tlayoutPill(def) {\n\t\t\tif (!def || typeof def !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (def.due || Array.isArray(def.variantWhen)) {\n\t\t\t\treturn this.datePill(def)\n\t\t\t}\n\t\t\tconst value = this.layoutText(def.field)\n\t\t\tif (value === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst labels = def.labels && typeof def.labels === 'object' ? def.labels : {}\n\t\t\tconst label = typeof labels[value] === 'string' ? this.cnTranslate(labels[value]) : value\n\t\t\tconst colorMap = def.colorMap && typeof def.colorMap === 'object' ? def.colorMap : {}\n\t\t\tconst key = Object.keys(colorMap).find((k) => k.toLowerCase() === value.toLowerCase())\n\t\t\tconst variant = key !== undefined ? colorMap[key] : def.variant\n\t\t\treturn this.withLook({ label, variant: isBadgeVariant(variant) ? variant : 'default' }, def)\n\t\t},\n\n\t\t/**\n\t\t * Lay the referenced record's tone and icon over a layout pill that\n\t\t * declares `resolve` (see `pillLooks`).\n\t\t *\n\t\t * @param {{label: string, variant: string}} pill The pill as declared.\n\t\t * @param {object} def The pill's definition.\n\t\t * @return {{label: string, variant: string, icon?: string}} The pill.\n\t\t * @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-card-pill-takes-its-tone-and-icon-from-the-referenced-record\n\t\t */\n\t\twithLook(pill, def) {\n\t\t\tif (!def || !def.resolve || !this.pillLooks || typeof this.pillLooks !== 'object') {\n\t\t\t\treturn pill\n\t\t\t}\n\t\t\tconst looks = this.pillLooks[def.field]\n\t\t\tconst raw = readPath(this.object, def.field)\n\t\t\tconst look = pillLook(looks && raw !== null && raw !== undefined ? looks[String(raw)] : null)\n\t\t\treturn { ...pill, ...(look.variant ? { variant: look.variant } : {}), ...(look.icon ? { icon: look.icon } : {}) }\n\t\t},\n\n\t\t/**\n\t\t * One fact of the card: the property's value with the matching page\n\t\t * column (label, formatter, widget) when there is one.\n\t\t *\n\t\t * @param {string} key The property key.\n\t\t * @param {object} prop The schema property.\n\t\t * @return {object} { key, label, value, property, column }\n\t\t */\n\t\tmetadataField(key, prop) {\n\t\t\tconst column = (this.cardFieldColumns && this.cardFieldColumns[key]) || null\n\t\t\treturn {\n\t\t\t\tkey,\n\t\t\t\tlabel: this.cnTranslate((column && column.label) || prop.title || key),\n\t\t\t\tvalue: this.object[key],\n\t\t\t\tproperty: prop,\n\t\t\t\tcolumn,\n\t\t\t}\n\t\t},\n\n\t\tformatValue,\n\n\t\t/**\n\t\t * Card-body click: emits `select` when `selectable` (ignoring drags),\n\t\t * otherwise emits `click` for navigation. With `clickToView`, a\n\t\t * selectable card's body click navigates too — the checkbox is the\n\t\t * only selection surface, mirroring the table's rowClickToView split.\n\t\t *\n\t\t * @param {MouseEvent} [event] The originating click event.\n\t\t */\n\t\tonCardClick(event) {\n\t\t\tif (this.selectable && !this.clickToView) {\n\t\t\t\tif (this.wasDrag(event)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event select Emitted when the card toggles selection (clicking the body of a selectable card, or its checkbox).\n\t\t\t\t * @type {object} The card's object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('select', this.object)\n\t\t\t\t// Deprecation: selectable cards used to emit `click`. Keep emitting it\n\t\t\t\t// for listeners that still rely on it, but warn them to migrate to `select`.\n\t\t\t\t// `$.vnode.props`, not `$attrs`: `click` is a declared emit, and\n\t\t\t\t// Vue keeps declared emits out of `$attrs`.\n\t\t\t\tif (this.$.vnode.props?.onClick) {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn('[CnObjectCard] @click on selectable cards is deprecated; use @select instead.')\n\t\t\t\t\tthis.$emit('click', this.object)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event click Emitted when a non-selectable (or `clickToView`) card is clicked. Payload: `(object, event)` — the card's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead. Selectable cards emit `select`; they also emit `click` (deprecated) when a `click` listener is present, so migrate selectable consumers to `@select`.\n\t\t\t * @type {object} The card's object.\n\t\t\t */\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\n\t\t/**\n\t\t * Card mousedown: record the press for the drag guard, and on a card a\n\t\t * middle click opens, keep the browser from starting autoscroll.\n\t\t *\n\t\t * @param {MouseEvent} event The mousedown event.\n\t\t */\n\t\tonCardMouseDown(event) {\n\t\t\tthis.onPointerDown(event)\n\t\t\tif (!this.selectable || this.clickToView) {\n\t\t\t\tpreventMiddleClickAutoscroll(event)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Card-body middle click: emits `aux-click`, not `click`, so an existing\n\t\t * `click` listener that navigates never moves the current tab away.\n\t\t * Ignored on a select-on-click card, on nested controls and on drags.\n\t\t *\n\t\t * @param {MouseEvent} event The auxclick event.\n\t\t */\n\t\tonCardAuxClick(event) {\n\t\t\tif (!isRowMiddleClick(event) || this.wasDrag(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.selectable && !this.clickToView) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event aux-click Emitted when a non-selectable (or `clickToView`) card is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the card's object and the native auxclick event.\n\t\t\t * @type {object} The card's object.\n\t\t\t */\n\t\t\tthis.$emit('aux-click', this.object, event)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-card {\n\tdisplay: flex;\n\tgap: 12px;\n\tpadding: 16px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 10px);\n\tcursor: pointer;\n\ttransition: box-shadow 0.2s ease, border-color 0.2s ease;\n}\n\n.cn-object-card:hover {\n\tborder-color: var(--color-primary-element);\n\tbox-shadow: 0 2px 8px var(--color-box-shadow);\n}\n\n.cn-object-card--selected {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n/* The 4px start border takes 3px of padding, so the content stays put. */\n.cn-object-card.cn-object-card--accent {\n\tborder-inline-start-width: 4px;\n\tpadding-inline-start: 13px;\n}\n\n.cn-object-card.cn-object-card--accent-success {\n\tborder-inline-start-color: var(--color-element-success);\n}\n\n.cn-object-card.cn-object-card--accent-warning {\n\tborder-inline-start-color: var(--color-element-warning);\n}\n\n.cn-object-card.cn-object-card--accent-error {\n\tborder-inline-start-color: var(--color-element-error);\n}\n\n.cn-object-card.cn-object-card--accent-info {\n\tborder-inline-start-color: var(--color-element-info);\n}\n\n.cn-object-card.cn-object-card--accent-primary {\n\tborder-inline-start-color: var(--color-primary-element);\n}\n\n.cn-object-card__accent-icon {\n\tdisplay: inline-flex;\n\tvertical-align: -2px;\n\tmargin-inline-end: 4px;\n}\n\n.cn-object-card--accent-success .cn-object-card__accent-icon {\n\tcolor: var(--color-text-success);\n}\n\n.cn-object-card--accent-warning .cn-object-card__accent-icon {\n\tcolor: var(--color-text-warning);\n}\n\n.cn-object-card--accent-error .cn-object-card__accent-icon {\n\tcolor: var(--color-text-error);\n}\n\n.cn-object-card--accent-info .cn-object-card__accent-icon {\n\tcolor: var(--color-element-info);\n}\n\n.cn-object-card--accent-primary .cn-object-card__accent-icon {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-object-card__checkbox {\n\tflex-shrink: 0;\n\tpadding-top: 2px;\n}\n\n.cn-object-card__content {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.cn-object-card__header {\n\tdisplay: flex;\n\tgap: 12px;\n\talign-items: flex-start;\n}\n\n.cn-object-card__image {\n\twidth: 48px;\n\theight: 48px;\n\tborder-radius: var(--border-radius);\n\tobject-fit: cover;\n\tflex-shrink: 0;\n}\n\n.cn-object-card__title-area {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.cn-object-card__title {\n\tmargin: 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tline-height: 1.3;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-card__description {\n\tmargin: 4px 0 0;\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n\tline-height: 1.4;\n}\n\n.cn-object-card__badges {\n\tmargin-top: 8px;\n}\n\n.cn-object-card__metadata {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fill, minmax(160px, 1fr));\n\tgap: 8px;\n\tmargin-top: 12px;\n\tpadding-top: 12px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-object-card__meta-item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-card__meta-label {\n\tfont-size: 11px;\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.3px;\n}\n\n.cn-object-card__actions {\n\tflex-shrink: 0;\n}\n</style>\n"],"names":["CnCellRenderer","CnIcon","CnLockIndicator","CnStatusBadge","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnObjectCard.vue2.js","sources":["../../../../src/components/CnObjectCard/CnObjectCard.vue"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-object-card\"\n\t\t:class=\"[{ 'cn-object-card--selected': selected, 'cn-object-card--board': isBoardLook }, accentVariant && ['cn-object-card--accent', `cn-object-card--accent-${accentVariant}`]]\"\n\t\t@mousedown=\"onCardMouseDown\"\n\t\t@click=\"onCardClick($event)\"\n\t\t@auxclick=\"onCardAuxClick($event)\">\n\t\t<!-- Selection checkbox (a record card draws it in its head row) -->\n\t\t<div v-if=\"selectable && !recordLayout\"\n\t\t\tclass=\"cn-object-card__checkbox\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t</div>\n\n\t\t<!-- Board look, record layout (`layout`): head pill and number, title,\n\t\t meta line, then a footer with a pill and a date. -->\n\t\t<div v-if=\"recordLayout\" class=\"cn-object-card__content cn-object-card__record\" data-testid=\"cn-object-card-record\">\n\t\t\t<div class=\"cn-object-card__record-head\">\n\t\t\t\t<div v-if=\"selectable\"\n\t\t\t\t\tclass=\"cn-object-card__checkbox\"\n\t\t\t\t\t@click.stop\n\t\t\t\t\t@auxclick.stop>\n\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t:modelValue=\"selected\"\n\t\t\t\t\t\t@update:modelValue=\"$emit('select', object)\" />\n\t\t\t\t</div>\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"recordHeadPill\"\n\t\t\t\t\tclass=\"cn-object-card__record-pill\"\n\t\t\t\t\t:label=\"recordHeadPill.label\"\n\t\t\t\t\t:variant=\"recordHeadPill.variant\"\n\t\t\t\t\tdata-testid=\"cn-object-card-head-pill\">\n\t\t\t\t\t<template v-if=\"recordHeadPill.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"recordHeadPill.icon\" :size=\"14\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnStatusBadge>\n\t\t\t\t<span v-if=\"recordNumber\" class=\"cn-object-card__record-number\" data-testid=\"cn-object-card-number\">{{ recordNumber }}</span>\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"$slots.actions\"\n\t\t\t\t\tclass=\"cn-object-card__menu\"\n\t\t\t\t\t@click.stop\n\t\t\t\t\t@auxclick.stop>\n\t\t\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<h3 class=\"cn-object-card__title\">\n\t\t\t\t<CnLockIndicator :object=\"object\" :size=\"16\" />\n\t\t\t\t{{ recordTitle }}\n\t\t\t</h3>\n\t\t\t<!-- A part whose field names a page column with a widget draws through\n\t\t\t it, as its table cell does; the rest are text. -->\n\t\t\t<p v-if=\"recordMetaParts.length > 0\" class=\"cn-object-card__record-meta\" data-testid=\"cn-object-card-meta\">\n\t\t\t\t<template v-for=\"(part, index) in recordMetaParts\" :key=\"part.field\">\n\t\t\t\t\t<span v-if=\"index > 0\" aria-hidden=\"true\"> · </span>\n\t\t\t\t\t<CnCellRenderer\n\t\t\t\t\t\tv-if=\"part.column && part.column.widget\"\n\t\t\t\t\t\t:value=\"part.value\"\n\t\t\t\t\t\t:widget=\"part.column.widget\"\n\t\t\t\t\t\t:widgetProps=\"part.column.widgetProps || undefined\"\n\t\t\t\t\t\t:formatter=\"part.column.formatter || null\"\n\t\t\t\t\t\t:formatterOptions=\"part.column.formatterOptions || null\"\n\t\t\t\t\t\t:row=\"object\" />\n\t\t\t\t\t<span v-else>{{ part.text }}</span>\n\t\t\t\t</template>\n\t\t\t</p>\n\t\t\t<p v-if=\"recordNote\"\n\t\t\t\tclass=\"cn-object-card__record-note\"\n\t\t\t\t:class=\"recordNote.tone ? 'cn-object-card__record-note--' + recordNote.tone : ''\"\n\t\t\t\tdata-testid=\"cn-object-card-note\">\n\t\t\t\t{{ recordNote.text }}\n\t\t\t</p>\n\t\t\t<p v-if=\"recordDescription\" class=\"cn-object-card__record-description\" data-testid=\"cn-object-card-description\">\n\t\t\t\t{{ recordDescription }}\n\t\t\t</p>\n\t\t\t<div v-if=\"recordChips.length > 0\" class=\"cn-object-card__record-chips\" data-testid=\"cn-object-card-chips\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-for=\"chip in recordChips\"\n\t\t\t\t\t:key=\"chip.field\"\n\t\t\t\t\tclass=\"cn-object-card__record-pill\"\n\t\t\t\t\t:label=\"chip.label\"\n\t\t\t\t\t:variant=\"chip.variant\">\n\t\t\t\t\t<template v-if=\"chip.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"chip.icon\" :size=\"14\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnStatusBadge>\n\t\t\t</div>\n\t\t\t<div v-if=\"$slots.badges\" class=\"cn-object-card__badges\">\n\t\t\t\t<slot name=\"badges\" :object=\"object\" />\n\t\t\t</div>\n\t\t\t<div v-if=\"recordFootPill || recordFootCell || recordDate\" class=\"cn-object-card__record-foot\" data-testid=\"cn-object-card-foot\">\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"recordFootPill\"\n\t\t\t\t\tclass=\"cn-object-card__record-pill\"\n\t\t\t\t\t:label=\"recordFootPill.label\"\n\t\t\t\t\t:variant=\"recordFootPill.variant\"\n\t\t\t\t\tdata-testid=\"cn-object-card-foot-pill\">\n\t\t\t\t\t<template v-if=\"recordFootPill.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"recordFootPill.icon\" :size=\"14\" />\n\t\t\t\t\t</template>\n\t\t\t\t</CnStatusBadge>\n\t\t\t\t<span v-if=\"recordFootCell\" class=\"cn-object-card__record-foot-cell\" data-testid=\"cn-object-card-foot-cell\">\n\t\t\t\t\t<CnCellRenderer\n\t\t\t\t\t\tv-if=\"recordFootCell.column && recordFootCell.column.widget\"\n\t\t\t\t\t\t:value=\"recordFootCell.value\"\n\t\t\t\t\t\t:widget=\"recordFootCell.column.widget\"\n\t\t\t\t\t\t:widgetProps=\"recordFootCell.column.widgetProps || undefined\"\n\t\t\t\t\t\t:formatter=\"recordFootCell.column.formatter || null\"\n\t\t\t\t\t\t:formatterOptions=\"recordFootCell.column.formatterOptions || null\"\n\t\t\t\t\t\t:row=\"object\" />\n\t\t\t\t\t<template v-else>{{ recordFootCell.text }}</template>\n\t\t\t\t</span>\n\t\t\t\t<!-- An empty footerCell keeps its place as a dash, as an empty table cell. -->\n\t\t\t\t<span\n\t\t\t\t\tv-else-if=\"recordFootCellDeclared\"\n\t\t\t\t\tclass=\"cn-object-card__record-foot-cell cn-object-card__record-foot-cell--empty\"\n\t\t\t\t\tdata-testid=\"cn-object-card-foot-cell-empty\">—</span>\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"recordDate\"\n\t\t\t\t\tclass=\"cn-object-card__record-date\"\n\t\t\t\t\t:class=\"[recordDateTone ? 'cn-object-card__record-date--' + recordDateTone : '']\"\n\t\t\t\t\tdata-testid=\"cn-object-card-date\">{{ recordDate }}</span>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Card content -->\n\t\t<div v-else class=\"cn-object-card__content\">\n\t\t\t<!-- Header: image + title -->\n\t\t\t<div class=\"cn-object-card__header\">\n\t\t\t\t<!-- Board look: the leading element, initials in a circle or an icon on a tint. -->\n\t\t\t\t<span\n\t\t\t\t\tv-if=\"isBoardLook && leadingKind\"\n\t\t\t\t\tclass=\"cn-object-card__leading\"\n\t\t\t\t\t:class=\"`cn-object-card__leading--${leadingKind}`\"\n\t\t\t\t\tdata-testid=\"cn-object-card-leading\"\n\t\t\t\t\taria-hidden=\"true\">\n\t\t\t\t\t<template v-if=\"leadingKind === 'initials'\">{{ leading.initials }}</template>\n\t\t\t\t\t<CnIcon v-else :name=\"leading.icon\" :size=\"20\" />\n\t\t\t\t</span>\n\t\t\t\t<img\n\t\t\t\t\tv-if=\"imageUrl\"\n\t\t\t\t\t:src=\"imageUrl\"\n\t\t\t\t\t:alt=\"title\"\n\t\t\t\t\tclass=\"cn-object-card__image\">\n\n\t\t\t\t<div class=\"cn-object-card__title-area\">\n\t\t\t\t\t<h3 class=\"cn-object-card__title\">\n\t\t\t\t\t\t<!-- Beside the title, not in the badges row: the badges\n\t\t\t\t\t\t slot is the consumer's, and a lock is the library's\n\t\t\t\t\t\t to report. A card whose consumer passes no badges\n\t\t\t\t\t\t would otherwise show no padlock at all. -->\n\t\t\t\t\t\t<CnLockIndicator :object=\"object\" :size=\"16\" />\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"accentVariant && accent.icon\"\n\t\t\t\t\t\t\tclass=\"cn-object-card__accent-icon\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-card-accent-icon\"\n\t\t\t\t\t\t\t:role=\"accent.label ? 'img' : null\"\n\t\t\t\t\t\t\t:aria-label=\"accent.label || null\"\n\t\t\t\t\t\t\t:aria-hidden=\"accent.label ? null : 'true'\"\n\t\t\t\t\t\t\t:title=\"accent.label || null\">\n\t\t\t\t\t\t\t<CnIcon :name=\"accent.icon\" :size=\"16\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t{{ title }}\n\t\t\t\t\t</h3>\n\t\t\t\t\t<p v-if=\"description\" class=\"cn-object-card__description\">\n\t\t\t\t\t\t{{ truncatedDescription }}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t\t<!-- Board look, end of the head: the status pill, or else the row menu. -->\n\t\t\t\t<template v-if=\"isBoardLook\">\n\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\tv-if=\"statusPill\"\n\t\t\t\t\t\tclass=\"cn-object-card__status\"\n\t\t\t\t\t\t:label=\"statusPill.label\"\n\t\t\t\t\t\t:variant=\"statusPill.variant\"\n\t\t\t\t\t\tdata-testid=\"cn-object-card-status\" />\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-else-if=\"$slots.actions\"\n\t\t\t\t\t\tclass=\"cn-object-card__menu\"\n\t\t\t\t\t\t@click.stop\n\t\t\t\t\t\t@auxclick.stop>\n\t\t\t\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t</div>\n\n\t\t\t<!-- Badges slot -->\n\t\t\t<div v-if=\"$slots.badges\" class=\"cn-object-card__badges\">\n\t\t\t\t<slot name=\"badges\" :object=\"object\" />\n\t\t\t</div>\n\n\t\t\t<!-- Metadata: visible properties as label:value pairs -->\n\t\t\t<div v-if=\"metadataFields.length > 0\" class=\"cn-object-card__metadata\" :class=\"{ 'cn-object-card__metadata--facts': isBoardLook }\">\n\t\t\t\t<slot name=\"metadata\" :object=\"object\" :fields=\"metadataFields\">\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-for=\"field in metadataFields\"\n\t\t\t\t\t\t:key=\"field.key\"\n\t\t\t\t\t\tclass=\"cn-object-card__meta-item\">\n\t\t\t\t\t\t<span class=\"cn-object-card__meta-label\">{{ field.label }}</span>\n\t\t\t\t\t\t<CnCellRenderer\n\t\t\t\t\t\t\t:value=\"field.value\"\n\t\t\t\t\t\t\t:property=\"field.property\"\n\t\t\t\t\t\t\t:formatter=\"field.column && field.column.formatter || null\"\n\t\t\t\t\t\t\t:formatterOptions=\"field.column && field.column.formatterOptions || null\"\n\t\t\t\t\t\t\t:widget=\"field.column && field.column.widget || null\"\n\t\t\t\t\t\t\t:widgetProps=\"field.column && field.column.widgetProps || undefined\"\n\t\t\t\t\t\t\t:row=\"object\"\n\t\t\t\t\t\t\t:truncate=\"60\" />\n\t\t\t\t\t</div>\n\t\t\t\t</slot>\n\t\t\t</div>\n\n\t\t\t<!-- Board look: one footer action, with a muted meta text at the start. -->\n\t\t\t<div\n\t\t\t\tv-if=\"isBoardLook && footerAction\"\n\t\t\t\tclass=\"cn-object-card__footer\"\n\t\t\t\tdata-testid=\"cn-object-card-footer\"\n\t\t\t\t@click.stop\n\t\t\t\t@auxclick.stop>\n\t\t\t\t<span v-if=\"footerAction.meta\" class=\"cn-object-card__footer-meta\">{{ footerAction.meta }}</span>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\tclass=\"cn-object-card__footer-action\"\n\t\t\t\t\tdata-testid=\"cn-object-card-footer-action\"\n\t\t\t\t\t:aria-label=\"footerAction.ariaLabel || `${footerAction.label} ${title}`\"\n\t\t\t\t\t@click=\"$emit('footer-action', object, footerAction)\">\n\t\t\t\t\t{{ footerAction.label }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Actions slot -->\n\t\t<div v-if=\"$slots.actions && !isBoardLook\"\n\t\t\tclass=\"cn-object-card__actions\"\n\t\t\t@click.stop\n\t\t\t@auxclick.stop>\n\t\t\t<slot name=\"actions\" :object=\"object\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch } from '@nextcloud/vue'\nimport { useClickDragGuard } from '../../composables/useClickDragGuard.js'\nimport { normalizeLook } from '../../composables/useLook.js'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { formatBoardDate } from '../../utils/boardDate.js'\nimport { resolveDateVariant } from '../../utils/dateVariant.js'\nimport { pillLook } from '../../utils/detailActionModel.js'\nimport { resolveDue } from '../../utils/dueText.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { resolveImageUrl } from '../../utils/resolveImageUrl.js'\nimport { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'\nimport { formatValue } from '../../utils/schema.js'\nimport { CnCellRenderer } from '../CnCellRenderer/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnLockIndicator } from '../CnLockIndicator/index.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\nconst ACCENT_VARIANTS = ['success', 'warning', 'error', 'info', 'primary']\n\n/**\n * CnObjectCard — Schema-configuration-driven card for object display.\n *\n * Uses `schema.configuration` to determine which fields map to the card title,\n * description, and image. Remaining visible properties are shown as metadata.\n *\n * ```vue\n * <CnObjectCard :object=\"publication\" :schema=\"pubSchema\">\n * <template #actions=\"{ object }\">\n * <NcActions><NcActionButton @click=\"edit(object)\">Edit</NcActionButton></NcActions>\n * </template>\n * </CnObjectCard>\n * ```\n */\nexport default {\n\tname: 'CnObjectCard',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tCnCellRenderer,\n\t\tCnIcon,\n\t\tCnLockIndicator,\n\t\tCnStatusBadge,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Consumer translation function, provided by CnAppRoot as\n\t\t * `cnTranslate: this.translate` (bound to the host app's id). Metadata\n\t\t * labels come from schema property titles, authored in English as the\n\t\t * canonical source; the visible label is resolved through this function\n\t\t * so it follows the user's language. Defaults to identity when used\n\t\t * standalone (no CnAppRoot ancestor).\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The look CnAppRoot provides; `board` draws the record card of the screens. */\n\t\tcnLook: { default: 'nextcloud' },\n\t\t/** The cell formatters CnAppRoot provides, for a layout part whose page column names one. */\n\t\tcnFormatters: { default: () => ({}) },\n\t},\n\n\tprops: {\n\t\t/** The object data */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema definition with properties and configuration */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether this card is selected */\n\t\tselected: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show selection checkbox */\n\t\tselectable: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * When true, a body click on a SELECTABLE card emits `click`\n\t\t * (navigation) instead of toggling selection — selection then happens\n\t\t * via the checkbox only. The card counterpart of CnIndexPage's\n\t\t * `rowClickToView` (a table row click already navigates in that mode).\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tclickToView: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the status pill at the end of the head row, as a label\n\t\t * (`\"Open\"`) or `{ label, variant }` with a CnStatusBadge variant\n\t\t * (`success`, `warning`, `error`, `info`, `primary`, `default`).\n\t\t * Without it the head row ends in the row menu, when there is one.\n\t\t *\n\t\t * @type {(string|{label: string, variant?: string})}\n\t\t * @spec openspec/changes/screens-card-parity/specs/card-board-look/spec.md#requirement-a-record-card-has-a-head-facts-and-one-action\n\t\t */\n\t\tstatus: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the leading element of the head row. `{ initials }`\n\t\t * draws the initials in a 36px circle; `{ icon }` a schema icon in a\n\t\t * 36px rounded square on a tint.\n\t\t *\n\t\t * @type {{initials?: string, icon?: string}}\n\t\t */\n\t\tleading: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the card's one footer action. `{ label, meta?,\n\t\t * ariaLabel? }`; `meta` is the 13px muted text at the start of the\n\t\t * footer. Clicking emits `footer-action`.\n\t\t *\n\t\t * @type {{label: string, meta?: string, ariaLabel?: string}}\n\t\t */\n\t\tfooterAction: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * A status accent: a colored border at the start of the card and,\n\t\t * with `icon`, a colored icon before the title. `variant` is one of\n\t\t * `success`, `warning`, `error`, `info` or `primary`; `icon` is a\n\t\t * name registered with CnIcon; `label` names the status for screen\n\t\t * readers and as the icon's tooltip.\n\t\t *\n\t\t * @type {{variant: string, icon?: string, label?: string}}\n\t\t */\n\t\taccent: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the record layout (manifest key `config.cardLayout`).\n\t\t * Every part names a field of the object (a dot path) and is left out\n\t\t * while that field is empty:\n\t\t * `{ headPill, number, title, meta, footerPill, footerDate }`.\n\t\t * A pill is `{ field, colorMap?, labels?, variant? }`: `colorMap` maps a\n\t\t * value to a CnStatusBadge variant (ignoring case), `labels` a value to\n\t\t * the text shown. `meta` is a list of fields, joined with \" · \".\n\t\t * `footerDate` is `{ field, label?, overdueVariant? }`, drawn as\n\t\t * \"Termijn 5 okt\", in `overdueVariant`'s tone (`error`) once the date\n\t\t * has passed. `description` is a field (or `{ field, maxLength? }`, cut\n\t\t * at 140 characters by default) drawn under the meta line. `chips` is a\n\t\t * list of `{ field, formatter?, formatterOptions?, colorMap?, labels?,\n\t\t * variant? }`, each a pill whose text reads through the formatter.\n\t\t * `note` is `{ field, formatter?, formatterOptions?, tone? }`, a line\n\t\t * under the meta line in the `purple` or `teal` pill ink.\n\t\t * Without it the card keeps its head, facts and action.\n\t\t *\n\t\t * @type {{headPill?: object, number?: string, title?: string, meta?: Array<string>, description?: (string|{field: string, maxLength?: number}), chips?: Array<object>, note?: {field: string, formatter?: string, formatterOptions?: object, tone?: string}, footerPill?: object, footerDate?: {field: string, label?: string, overdueVariant?: string}}}\n\t\t * @spec openspec/changes/board-record-card-layout/specs/board-record-card-layout/spec.md#requirement-a-board-card-can-draw-the-record-layout-from-config\n\t\t */\n\t\tlayout: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The referenced records' colour and icon names, by field and id\n\t\t * (`{ [field]: { [id]: { color, icon } } }`, CnIndexPage reads them).\n\t\t * A record layout pill with `resolve: { colorField?, iconField? }` takes\n\t\t * its record's tone and icon from here.\n\t\t *\n\t\t * @type {object}\n\t\t * @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-card-pill-takes-its-tone-and-icon-from-the-referenced-record\n\t\t */\n\t\tpillLooks: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The property keys the facts list shows, in order (manifest key\n\t\t * `config.cardFields`). Without it the card shows the first\n\t\t * `maxMetadata` visible properties, as before.\n\t\t *\n\t\t * @type {Array<string>}\n\t\t */\n\t\tcardFields: {\n\t\t\ttype: Array,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The page's columns by key: a fact whose key names a column renders\n\t\t * through that column's label, formatter and widget, as the table does.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcardFieldColumns: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Maximum number of metadata fields to show */\n\t\tmaxMetadata: {\n\t\t\ttype: Number,\n\t\t\tdefault: 4,\n\t\t},\n\t},\n\n\temits: ['click', 'select', 'aux-click', 'footer-action'],\n\n\tsetup() {\n\t\t// Tell a deliberate card click apart from a text-selection drag.\n\t\treturn useClickDragGuard()\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the record card of the board look is drawn.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tisBoardLook() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/**\n\t\t * `initials`, `icon` or '' for the head row's leading element.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tleadingKind() {\n\t\t\tif (this.leading && typeof this.leading.initials === 'string' && this.leading.initials !== '') {\n\t\t\t\treturn 'initials'\n\t\t\t}\n\t\t\treturn this.leading && typeof this.leading.icon === 'string' && this.leading.icon !== '' ? 'icon' : ''\n\t\t},\n\n\t\t/**\n\t\t * The status as `{ label, variant }`, or null.\n\t\t *\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\tstatusPill() {\n\t\t\tif (typeof this.status === 'string' && this.status !== '') {\n\t\t\t\treturn { label: this.status, variant: 'default' }\n\t\t\t}\n\t\t\tif (this.status && typeof this.status.label === 'string' && this.status.label !== '') {\n\t\t\t\treturn { label: this.status.label, variant: this.status.variant || 'default' }\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The record layout when the board look draws it, else null.\n\t\t *\n\t\t * @return {?object}\n\t\t * @spec openspec/changes/board-record-card-layout/specs/board-record-card-layout/spec.md#requirement-a-board-card-can-draw-the-record-layout-from-config\n\t\t */\n\t\trecordLayout() {\n\t\t\treturn this.isBoardLook && this.layout && typeof this.layout === 'object' ? this.layout : null\n\t\t},\n\n\t\t/**\n\t\t * The record layout's head pill, or null.\n\t\t *\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\trecordHeadPill() {\n\t\t\treturn this.recordLayout ? this.layoutPill(this.recordLayout.headPill) : null\n\t\t},\n\n\t\t/**\n\t\t * The record layout's footer pill, or null.\n\t\t *\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\trecordFootPill() {\n\t\t\treturn this.recordLayout ? this.layoutPill(this.recordLayout.footerPill) : null\n\t\t},\n\n\t\t/**\n\t\t * The record number at the end of the head, or ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\trecordNumber() {\n\t\t\treturn this.recordLayout ? this.layoutText(this.recordLayout.number) : ''\n\t\t},\n\n\t\t/**\n\t\t * The title: the layout's `title` field, else the card's own title.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\trecordTitle() {\n\t\t\tconst text = this.recordLayout ? this.layoutText(this.recordLayout.title) : ''\n\t\t\treturn text !== '' ? text : this.title\n\t\t},\n\n\t\t/**\n\t\t * The meta line: the layout's `meta` fields that hold a value, joined.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\trecordMeta() {\n\t\t\treturn this.recordMetaParts.map((part) => part.text).join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * The meta line's parts that hold a value: each with its text and, when\n\t\t * its field names a page column, that column (whose widget draws it).\n\t\t *\n\t\t * @return {Array<{field: string, value: unknown, text: string, column: ?object}>}\n\t\t */\n\t\trecordMetaParts() {\n\t\t\tconst fields = this.recordLayout && Array.isArray(this.recordLayout.meta) ? this.recordLayout.meta : []\n\t\t\treturn fields\n\t\t\t\t.map((part) => this.metaPart(part))\n\t\t\t\t.filter((part) => part !== null && part.text !== '')\n\t\t},\n\n\t\t/**\n\t\t * The `note` line under the meta line, read as a meta part is, with\n\t\t * its tone (`purple`, `teal`), or null while it is empty.\n\t\t *\n\t\t * @return {?{text: string, tone: string}}\n\t\t * @spec openspec/changes/card-layout-note/specs/card-layout-note/spec.md#requirement-a-record-card-can-draw-a-toned-note-under-its-meta-line\n\t\t */\n\t\trecordNote() {\n\t\t\tconst def = this.recordLayout ? this.recordLayout.note : null\n\t\t\tconst part = def ? this.metaPart(def) : null\n\t\t\tif (!part || part.text === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst tone = ['purple', 'teal'].includes(def.tone) ? def.tone : ''\n\t\t\treturn { text: part.text, tone }\n\t\t},\n\n\t\t/**\n\t\t * Whether the record layout names a `footerCell`, so an empty one\n\t\t * keeps its place.\n\t\t *\n\t\t * @spec openspec/changes/card-empty-footer-cell-dash/specs/card-empty-footer-cell-dash/spec.md#requirement-an-empty-footer-cell-reads-as-a-dash\n\t\t * @return {boolean}\n\t\t */\n\t\trecordFootCellDeclared() {\n\t\t\treturn Boolean(this.recordLayout && this.recordLayout.footerCell)\n\t\t},\n\n\t\t/**\n\t\t * The footer's `footerCell` part, read as a meta part is (through the\n\t\t * page column it names), or null while it is empty.\n\t\t *\n\t\t * @return {?{field: string, value: unknown, text: string, column: ?object}}\n\t\t */\n\t\trecordFootCell() {\n\t\t\tconst part = this.recordLayout ? this.metaPart(this.recordLayout.footerCell) : null\n\t\t\treturn part && part.text !== '' ? part : null\n\t\t},\n\n\t\t/**\n\t\t * The footer date with its label (\"Termijn 5 okt\"), or ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\trecordDate() {\n\t\t\tconst def = this.recordLayout ? this.recordLayout.footerDate : null\n\t\t\tif (!def || typeof def.field !== 'string') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst date = formatBoardDate(readPath(this.object, def.field))\n\t\t\tif (date === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof def.label === 'string' && def.label !== '' ? `${this.cnTranslate(def.label)} ${date}` : date\n\t\t},\n\n\t\t/**\n\t\t * The tone of the footer date: `overdueVariant` once the date has\n\t\t * passed, else ''.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/saved-view-overrides/specs/saved-views-ui/spec.md#requirement-a-board-card-can-draw-a-description-chips-and-an-overdue-date\n\t\t */\n\t\trecordDateTone() {\n\t\t\tconst def = this.recordLayout ? this.recordLayout.footerDate : null\n\t\t\tif (!def || typeof def.field !== 'string' || typeof def.overdueVariant !== 'string' || def.overdueVariant === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn this.dueVariant(readPath(this.object, def.field), {}) === 'error' ? def.overdueVariant : ''\n\t\t},\n\n\t\t/**\n\t\t * The description line, cut at `maxLength` characters (140 by\n\t\t * default) with an ellipsis, or ''.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/saved-view-overrides/specs/saved-views-ui/spec.md#requirement-a-board-card-can-draw-a-description-chips-and-an-overdue-date\n\t\t */\n\t\trecordDescription() {\n\t\t\tconst def = this.recordLayout ? this.recordLayout.description : null\n\t\t\tconst field = typeof def === 'string' ? def : (def && typeof def.field === 'string' ? def.field : '')\n\t\t\tconst text = this.layoutText(field).trim()\n\t\t\tconst max = def && typeof def === 'object' && Number.isInteger(def.maxLength) && def.maxLength > 0 ? def.maxLength : 140\n\t\t\treturn text.length > max ? `${text.slice(0, max).trimEnd()}…` : text\n\t\t},\n\n\t\t/**\n\t\t * The chips: one pill per `chips` entry whose field holds a value, its\n\t\t * text read through the entry's formatter (a status uuid as its name).\n\t\t *\n\t\t * @return {Array<{field: string, label: string, variant: string}>}\n\t\t * @spec openspec/changes/saved-view-overrides/specs/saved-views-ui/spec.md#requirement-a-board-card-can-draw-a-description-chips-and-an-overdue-date\n\t\t */\n\t\trecordChips() {\n\t\t\tconst chips = this.recordLayout && Array.isArray(this.recordLayout.chips) ? this.recordLayout.chips : []\n\t\t\treturn chips\n\t\t\t\t.map((def) => (typeof def === 'string' ? { field: def } : def))\n\t\t\t\t.filter((def) => def && typeof def.field === 'string' && def.field !== '')\n\t\t\t\t.map((def) => {\n\t\t\t\t\tconst column = typeof def.formatter === 'string' ? { formatter: def.formatter, formatterOptions: def.formatterOptions } : undefined\n\t\t\t\t\tconst label = this.layoutText(def.field, column)\n\t\t\t\t\tif (label === '') {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\tconst raw = readPath(this.object, def.field)\n\t\t\t\t\tconst mapped = def.colorMap && typeof def.colorMap === 'object' ? def.colorMap[String(raw)] || def.colorMap[String(raw).toLowerCase()] : undefined\n\t\t\t\t\tconst labels = def.labels && typeof def.labels === 'object' ? def.labels : {}\n\t\t\t\t\tconst shown = typeof labels[String(raw)] === 'string' ? this.cnTranslate(labels[String(raw)]) : label\n\t\t\t\t\tconst variant = mapped || def.variant\n\t\t\t\t\treturn this.withLook({ field: def.field, label: shown, variant: isBadgeVariant(variant) ? variant : 'default' }, def)\n\t\t\t\t})\n\t\t\t\t.filter(Boolean)\n\t\t},\n\n\t\t/**\n\t\t * The accent variant when it is a known one, else ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\taccentVariant() {\n\t\t\tconst variant = this.accent?.variant\n\t\t\treturn ACCENT_VARIANTS.includes(variant) ? variant : ''\n\t\t},\n\n\t\tconfig() {\n\t\t\treturn this.schema?.configuration || {}\n\t\t},\n\n\t\ttitle() {\n\t\t\tconst field = this.config.objectNameField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn this.object.title || this.object.name || this.object.id || '—'\n\t\t},\n\n\t\tdescription() {\n\t\t\tconst field = this.config.objectDescriptionField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn String(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\ttruncatedDescription() {\n\t\t\tif (!this.description) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (this.description.length > 120) {\n\t\t\t\treturn this.description.substring(0, 120) + '...'\n\t\t\t}\n\t\t\treturn this.description\n\t\t},\n\n\t\timageUrl() {\n\t\t\tconst field = this.config.objectImageField\n\t\t\tif (field && this.object[field]) {\n\t\t\t\treturn resolveImageUrl(this.object[field])\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/** Fields excluded from metadata (already shown as title/desc/image) */\n\t\tconfigFields() {\n\t\t\treturn [\n\t\t\t\tthis.config.objectNameField,\n\t\t\t\tthis.config.objectDescriptionField,\n\t\t\t\tthis.config.objectSummaryField,\n\t\t\t\tthis.config.objectImageField,\n\t\t\t].filter(Boolean)\n\t\t},\n\n\t\t/** Remaining visible properties for the metadata section */\n\t\tmetadataFields() {\n\t\t\tif (!this.schema?.properties) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\t// The page names the facts: those properties, in that order.\n\t\t\tif (Array.isArray(this.cardFields)) {\n\t\t\t\treturn this.cardFields\n\t\t\t\t\t.filter((key) => typeof key === 'string' && this.schema.properties[key] && !this.configFields.includes(key))\n\t\t\t\t\t.map((key) => this.metadataField(key, this.schema.properties[key]))\n\t\t\t}\n\n\t\t\treturn Object.entries(this.schema.properties)\n\t\t\t\t.filter(([key, prop]) => {\n\t\t\t\t\tif (this.configFields.includes(key)) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\tif (prop.visible === false) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\tif (prop.type === 'object') {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\tif (prop.format === 'markdown') {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\treturn true\n\t\t\t\t})\n\t\t\t\t.sort(([, a], [, b]) => {\n\t\t\t\t\tconst orderA = typeof a.order === 'number' ? a.order : Infinity\n\t\t\t\t\tconst orderB = typeof b.order === 'number' ? b.order : Infinity\n\t\t\t\t\treturn orderA - orderB\n\t\t\t\t})\n\t\t\t\t.slice(0, this.maxMetadata)\n\t\t\t\t.map(([key, prop]) => this.metadataField(key, prop))\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * One meta part: a field name reads through the page column it names;\n\t\t * `{ field, formatter?, formatterOptions? }` reads as plain text through\n\t\t * its own formatter, so a column's widget (a badge) stays in the table.\n\t\t *\n\t\t * @param {string|{field: string, formatter?: string, formatterOptions?: object}} part The part.\n\t\t * @return {?{field: string, value: unknown, text: string, column: ?object}} The part, or null when it names no field.\n\t\t * @spec openspec/changes/card-layout-part-formatter/specs/card-layout-part-formatter/spec.md#requirement-a-card-meta-part-can-name-its-own-formatter\n\t\t */\n\t\tmetaPart(part) {\n\t\t\tif (typeof part === 'string' && part !== '') {\n\t\t\t\treturn { field: part, value: readPath(this.object, part), text: this.layoutText(part), column: this.layoutColumn(part) }\n\t\t\t}\n\t\t\tif (!part || typeof part !== 'object' || typeof part.field !== 'string' || part.field === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst column = typeof part.formatter === 'string' ? { formatter: part.formatter, formatterOptions: part.formatterOptions } : null\n\t\t\treturn { field: part.field, value: readPath(this.object, part.field), text: this.layoutText(part.field, column), column }\n\t\t},\n\n\t\t/**\n\t\t * A field's value as text: a person or a record by its display name,\n\t\t * title or name, anything else as a string. '' for an empty value or\n\t\t * a field that is not named.\n\t\t *\n\t\t * @param {unknown} field A dot path into the object.\n\t\t * @param {?object} [own] The column to read through instead of the one the field names.\n\t\t * @return {string}\n\t\t */\n\t\tlayoutText(field, own) {\n\t\t\tif (typeof field !== 'string' || field === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst value = readPath(this.object, field)\n\t\t\tif (value === null || value === undefined || value === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\t// A part whose field names a page column with a formatter reads as\n\t\t\t// its table cell does (a case type uuid as its name).\n\t\t\tconst column = own === undefined ? this.layoutColumn(field) : own\n\t\t\tconst format = column && column.formatter && this.cnFormatters ? this.cnFormatters[column.formatter] : null\n\t\t\tif (typeof format === 'function') {\n\t\t\t\tconst formatted = format(value, this.object, this.schema?.properties?.[field], column.formatterOptions || undefined)\n\t\t\t\treturn formatted === null || formatted === undefined ? '' : String(formatted)\n\t\t\t}\n\t\t\tif (typeof value === 'object') {\n\t\t\t\tconst name = value.displayName || value.title || value.name\n\t\t\t\treturn typeof name === 'string' ? name : ''\n\t\t\t}\n\t\t\treturn String(value)\n\t\t},\n\n\t\t/**\n\t\t * The page column a layout part's field names, or null.\n\t\t *\n\t\t * @param {string} field The part's field.\n\t\t * @return {?object} The column.\n\t\t */\n\t\tlayoutColumn(field) {\n\t\t\treturn (this.cardFieldColumns && typeof field === 'string' && this.cardFieldColumns[field]) || null\n\t\t},\n\n\t\t/**\n\t\t * A pill that reads its date field through the due rules: `variantWhen`\n\t\t * (the first rule the days left match gives the tone), else `due`\n\t\t * (overdue reads as error, within `due.soonWithin` days as warning).\n\t\t * The label is `labels[variant]`, else `labels.overdue` / `labels.soon`,\n\t\t * else Overdue / Soon, through the host's translate. Any other date\n\t\t * draws no pill.\n\t\t *\n\t\t * @param {{field: string, due?: object, variantWhen?: Array, labels?: object}} def The pill.\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\tdatePill(def) {\n\t\t\tconst value = readPath(this.object, def.field)\n\t\t\tconst variant = Array.isArray(def.variantWhen)\n\t\t\t\t? this.dateRuleVariant(value, def.variantWhen)\n\t\t\t\t: this.dueVariant(value, def.due)\n\t\t\tif (variant === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst labels = def.labels && typeof def.labels === 'object' ? def.labels : {}\n\t\t\tconst state = variant === 'error' ? 'overdue' : (variant === 'warning' ? 'soon' : '')\n\t\t\tconst authored = labels[variant] || (state && labels[state])\n\t\t\tif (typeof authored === 'string' && authored !== '') {\n\t\t\t\treturn { label: this.cnTranslate(authored), variant }\n\t\t\t}\n\t\t\tif (state === 'overdue') {\n\t\t\t\treturn { label: t('nextcloud-vue', 'Overdue'), variant }\n\t\t\t}\n\t\t\tif (state === 'soon') {\n\t\t\t\treturn { label: t('nextcloud-vue', 'Soon'), variant }\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The variant of the first `variantWhen` rule a date matches, or ''.\n\t\t *\n\t\t * @param {unknown} value The date.\n\t\t * @param {Array} rules The rules.\n\t\t * @return {string} The variant, or ''.\n\t\t */\n\t\tdateRuleVariant(value, rules) {\n\t\t\tconst matched = resolveDateVariant(value, rules)\n\t\t\treturn matched === 'default' ? '' : matched\n\t\t},\n\n\t\t/**\n\t\t * The variant the due rules give a date: error when overdue, warning\n\t\t * within `soonWithin` days, else ''.\n\t\t *\n\t\t * @param {unknown} value The date.\n\t\t * @param {object} config The `due` config.\n\t\t * @return {string} The variant, or ''.\n\t\t */\n\t\tdueVariant(value, config) {\n\t\t\tconst due = resolveDue(value, config)\n\t\t\tif (due && due.tone === 'danger') {\n\t\t\t\treturn 'error'\n\t\t\t}\n\t\t\treturn due && due.soon ? 'warning' : ''\n\t\t},\n\n\t\t/**\n\t\t * A layout pill as `{ label, variant }`, or null while its field is\n\t\t * empty.\n\t\t *\n\t\t * @param {?{field: string, colorMap?: object, labels?: object, variant?: string}} def The pill.\n\t\t * @return {?{label: string, variant: string}}\n\t\t */\n\t\tlayoutPill(def) {\n\t\t\tif (!def || typeof def !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (def.due || Array.isArray(def.variantWhen)) {\n\t\t\t\treturn this.datePill(def)\n\t\t\t}\n\t\t\tconst value = this.layoutText(def.field)\n\t\t\tif (value === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst labels = def.labels && typeof def.labels === 'object' ? def.labels : {}\n\t\t\tconst label = typeof labels[value] === 'string' ? this.cnTranslate(labels[value]) : value\n\t\t\tconst colorMap = def.colorMap && typeof def.colorMap === 'object' ? def.colorMap : {}\n\t\t\tconst key = Object.keys(colorMap).find((k) => k.toLowerCase() === value.toLowerCase())\n\t\t\tconst variant = key !== undefined ? colorMap[key] : def.variant\n\t\t\treturn this.withLook({ label, variant: isBadgeVariant(variant) ? variant : 'default' }, def)\n\t\t},\n\n\t\t/**\n\t\t * Lay the referenced record's tone and icon over a layout pill that\n\t\t * declares `resolve` (see `pillLooks`).\n\t\t *\n\t\t * @param {{label: string, variant: string}} pill The pill as declared.\n\t\t * @param {object} def The pill's definition.\n\t\t * @return {{label: string, variant: string, icon?: string}} The pill.\n\t\t * @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-card-pill-takes-its-tone-and-icon-from-the-referenced-record\n\t\t */\n\t\twithLook(pill, def) {\n\t\t\tif (!def || !def.resolve || !this.pillLooks || typeof this.pillLooks !== 'object') {\n\t\t\t\treturn pill\n\t\t\t}\n\t\t\tconst looks = this.pillLooks[def.field]\n\t\t\tconst raw = readPath(this.object, def.field)\n\t\t\tconst look = pillLook(looks && raw !== null && raw !== undefined ? looks[String(raw)] : null)\n\t\t\treturn { ...pill, ...(look.variant ? { variant: look.variant } : {}), ...(look.icon ? { icon: look.icon } : {}) }\n\t\t},\n\n\t\t/**\n\t\t * One fact of the card: the property's value with the matching page\n\t\t * column (label, formatter, widget) when there is one.\n\t\t *\n\t\t * @param {string} key The property key.\n\t\t * @param {object} prop The schema property.\n\t\t * @return {object} { key, label, value, property, column }\n\t\t */\n\t\tmetadataField(key, prop) {\n\t\t\tconst column = (this.cardFieldColumns && this.cardFieldColumns[key]) || null\n\t\t\treturn {\n\t\t\t\tkey,\n\t\t\t\tlabel: this.cnTranslate((column && column.label) || prop.title || key),\n\t\t\t\tvalue: this.object[key],\n\t\t\t\tproperty: prop,\n\t\t\t\tcolumn,\n\t\t\t}\n\t\t},\n\n\t\tformatValue,\n\n\t\t/**\n\t\t * Card-body click: emits `select` when `selectable` (ignoring drags),\n\t\t * otherwise emits `click` for navigation. With `clickToView`, a\n\t\t * selectable card's body click navigates too — the checkbox is the\n\t\t * only selection surface, mirroring the table's rowClickToView split.\n\t\t *\n\t\t * @param {MouseEvent} [event] The originating click event.\n\t\t */\n\t\tonCardClick(event) {\n\t\t\tif (this.selectable && !this.clickToView) {\n\t\t\t\tif (this.wasDrag(event)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * @event select Emitted when the card toggles selection (clicking the body of a selectable card, or its checkbox).\n\t\t\t\t * @type {object} The card's object.\n\t\t\t\t */\n\t\t\t\tthis.$emit('select', this.object)\n\t\t\t\t// Deprecation: selectable cards used to emit `click`. Keep emitting it\n\t\t\t\t// for listeners that still rely on it, but warn them to migrate to `select`.\n\t\t\t\t// `$.vnode.props`, not `$attrs`: `click` is a declared emit, and\n\t\t\t\t// Vue keeps declared emits out of `$attrs`.\n\t\t\t\tif (this.$.vnode.props?.onClick) {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn('[CnObjectCard] @click on selectable cards is deprecated; use @select instead.')\n\t\t\t\t\tthis.$emit('click', this.object)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event click Emitted when a non-selectable (or `clickToView`) card is clicked. Payload: `(object, event)` — the card's object and the native click event, for opening it in a new tab on a ctrl/cmd/shift click. A middle click emits `aux-click` instead. Selectable cards emit `select`; they also emit `click` (deprecated) when a `click` listener is present, so migrate selectable consumers to `@select`.\n\t\t\t * @type {object} The card's object.\n\t\t\t */\n\t\t\tthis.$emit('click', this.object, event)\n\t\t},\n\n\t\t/**\n\t\t * Card mousedown: record the press for the drag guard, and on a card a\n\t\t * middle click opens, keep the browser from starting autoscroll.\n\t\t *\n\t\t * @param {MouseEvent} event The mousedown event.\n\t\t */\n\t\tonCardMouseDown(event) {\n\t\t\tthis.onPointerDown(event)\n\t\t\tif (!this.selectable || this.clickToView) {\n\t\t\t\tpreventMiddleClickAutoscroll(event)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Card-body middle click: emits `aux-click`, not `click`, so an existing\n\t\t * `click` listener that navigates never moves the current tab away.\n\t\t * Ignored on a select-on-click card, on nested controls and on drags.\n\t\t *\n\t\t * @param {MouseEvent} event The auxclick event.\n\t\t */\n\t\tonCardAuxClick(event) {\n\t\t\tif (!isRowMiddleClick(event) || this.wasDrag(event)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.selectable && !this.clickToView) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event aux-click Emitted when a non-selectable (or `clickToView`) card is middle-clicked, for opening it in a new tab (see `openRowTarget`). Payload: `(object, event)` — the card's object and the native auxclick event.\n\t\t\t * @type {object} The card's object.\n\t\t\t */\n\t\t\tthis.$emit('aux-click', this.object, event)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-card {\n\tdisplay: flex;\n\tgap: 12px;\n\tpadding: 16px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 10px);\n\tcursor: pointer;\n\ttransition: box-shadow 0.2s ease, border-color 0.2s ease;\n}\n\n.cn-object-card:hover {\n\tborder-color: var(--color-primary-element);\n\tbox-shadow: 0 2px 8px var(--color-box-shadow);\n}\n\n.cn-object-card--selected {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n/* The 4px start border takes 3px of padding, so the content stays put. */\n.cn-object-card.cn-object-card--accent {\n\tborder-inline-start-width: 4px;\n\tpadding-inline-start: 13px;\n}\n\n.cn-object-card.cn-object-card--accent-success {\n\tborder-inline-start-color: var(--color-element-success);\n}\n\n.cn-object-card.cn-object-card--accent-warning {\n\tborder-inline-start-color: var(--color-element-warning);\n}\n\n.cn-object-card.cn-object-card--accent-error {\n\tborder-inline-start-color: var(--color-element-error);\n}\n\n.cn-object-card.cn-object-card--accent-info {\n\tborder-inline-start-color: var(--color-element-info);\n}\n\n.cn-object-card.cn-object-card--accent-primary {\n\tborder-inline-start-color: var(--color-primary-element);\n}\n\n.cn-object-card__accent-icon {\n\tdisplay: inline-flex;\n\tvertical-align: -2px;\n\tmargin-inline-end: 4px;\n}\n\n.cn-object-card--accent-success .cn-object-card__accent-icon {\n\tcolor: var(--color-text-success);\n}\n\n.cn-object-card--accent-warning .cn-object-card__accent-icon {\n\tcolor: var(--color-text-warning);\n}\n\n.cn-object-card--accent-error .cn-object-card__accent-icon {\n\tcolor: var(--color-text-error);\n}\n\n.cn-object-card--accent-info .cn-object-card__accent-icon {\n\tcolor: var(--color-element-info);\n}\n\n.cn-object-card--accent-primary .cn-object-card__accent-icon {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-object-card__checkbox {\n\tflex-shrink: 0;\n\tpadding-top: 2px;\n}\n\n.cn-object-card__content {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.cn-object-card__header {\n\tdisplay: flex;\n\tgap: 12px;\n\talign-items: flex-start;\n}\n\n.cn-object-card__image {\n\twidth: 48px;\n\theight: 48px;\n\tborder-radius: var(--border-radius);\n\tobject-fit: cover;\n\tflex-shrink: 0;\n}\n\n.cn-object-card__title-area {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.cn-object-card__title {\n\tmargin: 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tline-height: 1.3;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-object-card__description {\n\tmargin: 4px 0 0;\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n\tline-height: 1.4;\n}\n\n.cn-object-card__badges {\n\tmargin-top: 8px;\n}\n\n.cn-object-card__metadata {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fill, minmax(160px, 1fr));\n\tgap: 8px;\n\tmargin-top: 12px;\n\tpadding-top: 12px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-object-card__meta-item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-object-card__meta-label {\n\tfont-size: 11px;\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\ttext-transform: uppercase;\n\tletter-spacing: 0.3px;\n}\n\n.cn-object-card__actions {\n\tflex-shrink: 0;\n}\n</style>\n"],"names":["CnCellRenderer","CnIcon","CnLockIndicator","CnStatusBadge","t"],"mappings":"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"}
|