@conduction/nextcloud-vue 2.143.0 → 2.144.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +7 -2
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
  5. package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
  6. package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
  7. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +1 -1
  8. package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
  9. package/dist/esm/components/CnEventsCard/CnEventsCard.vue.js +1 -1
  10. package/dist/esm/components/CnEventsCard/CnEventsCard.vue2.js +9 -0
  11. package/dist/esm/components/CnEventsCard/CnEventsCard.vue2.js.map +1 -1
  12. package/dist/esm/components/CnEventsCard/CnEventsCard.vue3.js +24 -13
  13. package/dist/esm/components/CnEventsCard/CnEventsCard.vue3.js.map +1 -1
  14. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  15. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +2 -1
  16. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  17. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  18. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +3 -1
  19. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  20. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  21. package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
  22. package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +3 -0
  23. package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
  24. package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js +19 -14
  25. package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
  26. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue.js +1 -1
  27. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js +30 -0
  28. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js.map +1 -1
  29. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js +158 -102
  30. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js.map +1 -1
  31. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
  32. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
  33. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js +12 -0
  34. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
  35. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue.js +1 -1
  36. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +110 -2
  37. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  38. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +146 -80
  39. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  40. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue.js +1 -1
  41. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js +45 -0
  42. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js.map +1 -1
  43. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js +67 -34
  44. package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js.map +1 -1
  45. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue.js +1 -1
  46. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js +3 -22
  47. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js.map +1 -1
  48. package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue3.js.map +1 -1
  49. package/dist/esm/integrations/builtin/calendar/eventStatus.js +67 -0
  50. package/dist/esm/integrations/builtin/calendar/eventStatus.js.map +1 -0
  51. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue.js +1 -1
  52. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +39 -0
  53. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
  54. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js +81 -32
  55. package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
  56. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue.js +1 -1
  57. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +5 -6
  58. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
  59. package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
  60. package/dist/esm/integrations/builtin/deck/deckCardParts.js +59 -0
  61. package/dist/esm/integrations/builtin/deck/deckCardParts.js.map +1 -0
  62. package/dist/esm/l10n/en.json.js +6 -0
  63. package/dist/esm/l10n/en.json.js.map +1 -1
  64. package/dist/esm/l10n/nl.json.js +6 -0
  65. package/dist/esm/l10n/nl.json.js.map +1 -1
  66. package/dist/esm/library-style.js +1 -1
  67. package/dist/esm/nextcloud-vue.css +815 -363
  68. package/dist/esm/utils/fetchFilterCounts.js +5 -2
  69. package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
  70. package/dist/esm/utils/nextcloudDirectory.js +19 -6
  71. package/dist/esm/utils/nextcloudDirectory.js.map +1 -1
  72. package/dist/nextcloud-vue.cjs.js +1347 -758
  73. package/dist/nextcloud-vue.cjs.js.map +2 -2
  74. package/dist/nextcloud-vue.css +815 -363
  75. package/l10n/en.json +6 -0
  76. package/l10n/nl.json +6 -0
  77. package/package.json +1 -1
  78. package/src/components/CnActionDialog/CnActionDialog.vue +28 -3
  79. package/src/components/CnConversationThread/CnConversationThread.vue +5 -2
  80. package/src/components/CnEventsCard/CnEventsCard.vue +27 -5
  81. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +15 -1
  82. package/src/components/CnIndexPage/CnIndexPage.vue +3 -1
  83. package/src/components/CnNotesCard/CnNotesCard.vue +8 -0
  84. package/src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue +114 -46
  85. package/src/components/CnRetentionWidget/CnRetentionWidget.vue +26 -1
  86. package/src/components/CnTasksWidget/CnTasksWidget.vue +170 -13
  87. package/src/css/dialog.css +7 -1
  88. package/src/css/kpi-card.css +3 -0
  89. package/src/css/look-board-detail.css +317 -0
  90. package/src/css/look-board-index.css +14 -0
  91. package/src/css/look-board.css +25 -0
  92. package/src/integrations/builtin/calendar/CnCalendarCard.vue +76 -11
  93. package/src/integrations/builtin/calendar/CnCalendarTab.vue +3 -22
  94. package/src/integrations/builtin/calendar/__tests__/CnCalendarCardBoardRows.spec.js +52 -0
  95. package/src/integrations/builtin/calendar/eventStatus.js +63 -0
  96. package/src/integrations/builtin/deck/CnDeckCard.vue +66 -0
  97. package/src/integrations/builtin/deck/CnDeckTab.vue +5 -6
  98. package/src/integrations/builtin/deck/__tests__/CnDeckCardBoardRows.spec.js +49 -0
  99. package/src/integrations/builtin/deck/deckCardParts.js +56 -0
  100. package/src/utils/fetchFilterCounts.js +5 -2
  101. package/src/utils/nextcloudDirectory.js +19 -6
@@ -1 +1 @@
1
- {"version":3,"file":"CnDeckCard.vue2.js","sources":["../../../../../src/integrations/builtin/deck/CnDeckCard.vue"],"sourcesContent":["<!--\n CnDeckCard — bespoke surface-aware widget for the `deck` integration.\n\n Replaces the generic CnIntegrationCard for the `deck` leaf. Branches on\n `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N cards across M stacks\";\n secondary line names the most recent card.\n - detail-page : mini three-column kanban view of\n the linked card's board with the linked card highlighted in its\n current stack (per design.md AD-2).\n - single-entity : chip with card title + stack name\n (referenceType: 'deck').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnDeckTab; for `single-entity` the optional `value` prop addresses a\n single card by id (matching CnIntegrationCard's fetchSingle contract).\n\n See `openregister/openspec/changes/integration-deck/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback),\n AD-2 (mini-kanban on detail-page).\n-->\n<template>\n\t<CnDetailCard :title=\"cardHeaderTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<!-- `headerActions`: the Deck tab's link and create flows in the title row (detail page). -->\n\t\t<template v-if=\"shownHeaderActions.length > 0\" #actions>\n\t\t\t<NcButton\n\t\t\t\tv-for=\"action in shownHeaderActions\"\n\t\t\t\t:key=\"action\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:data-testid=\"`cn-deck-card-${action}`\"\n\t\t\t\t@click.stop=\"action === 'create' ? (createOpen = true) : (pickerOpen = true)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus v-if=\"action === 'create'\" :size=\"20\" />\n\t\t\t\t\t<LinkVariant v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ action === 'create' ? createLabel : linkLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span v-if=\"entity\" class=\"cn-deck-card__chip\" :title=\"chipSubtitle(entity)\">\n\t\t\t\t<ViewColumnOutline :size=\"14\" />\n\t\t\t\t<a\n\t\t\t\t\t:href=\"cardUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ cardTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"stackTitle(entity)\" class=\"cn-deck-card__chip-stack\">\n\t\t\t\t\t· {{ stackTitle(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-deck-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: headline + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"cards.length === 0\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-deck-card__headline\">\n\t\t\t\t<div class=\"cn-deck-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<ul v-if=\"stackDistribution.length > 0\" class=\"cn-deck-card__distribution\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"bucket in stackDistribution\"\n\t\t\t\t\t\t:key=\"bucket.key\"\n\t\t\t\t\t\tclass=\"cn-deck-card__distribution-row\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__distribution-label\">{{ bucket.label }}</span>\n\t\t\t\t\t\t<span class=\"cn-deck-card__distribution-count\">{{ bucket.count }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-deck-card__headline-recent\">\n\t\t\t\t\t<ViewColumnOutline :size=\"14\" />\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"cardUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ cardTitle(mostRecent) }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: mini-kanban -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"cards.length === 0\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-deck-card__kanban\">\n\t\t\t\t<section\n\t\t\t\t\tv-for=\"stack in miniColumns\"\n\t\t\t\t\t:key=\"stack.key\"\n\t\t\t\t\tclass=\"cn-deck-card__column\">\n\t\t\t\t\t<header class=\"cn-deck-card__column-header\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__column-title\">{{ stack.label }}</span>\n\t\t\t\t\t\t<span class=\"cn-deck-card__column-count\">{{ stack.cards.length }}</span>\n\t\t\t\t\t</header>\n\t\t\t\t\t<ul class=\"cn-deck-card__column-list\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"card in stack.cards\"\n\t\t\t\t\t\t\t:key=\"cardKey(card)\"\n\t\t\t\t\t\t\tclass=\"cn-deck-card__row\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-deck-card__row--highlight': isLinked(card) }\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t:href=\"cardUrl(card)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\t\tclass=\"cn-deck-card__title\">{{ cardTitle(card) }}</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</section>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<p v-if=\"actionError\" class=\"cn-deck-card__action-error\" role=\"alert\">\n\t\t\t{{ actionError }}\n\t\t</p>\n\n\t\t<CnDeckCardPicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLink\" />\n\n\t\t<CnDeckCardCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreate\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport ViewColumnOutline from 'vue-material-design-icons/ViewColumnOutline.vue'\nimport CnDeckCardCreate from '../../../components/CnDeckCardCreate/CnDeckCardCreate.vue'\nimport CnDeckCardPicker from '../../../components/CnDeckCardPicker/CnDeckCardPicker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\n\n/**\n * CnDeckCard — bespoke surface-aware widget for the `deck` integration.\n *\n * Renders Deck-aware metadata across all four surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnDeckCard',\n\n\tcomponents: { CnDeckCardCreate, CnDeckCardPicker, CnDetailCard, LinkVariant, NcButton, NcLoadingIcon, Plus, ViewColumnOutline },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'deck'`). */\n\t\tintegrationId: { type: String, default: 'deck' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (card id). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Cards') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => ViewColumnOutline },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No cards linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Deck is currently unavailable.') },\n\t\t/** URL of the NC Deck app entry. */\n\t\tdeckAppUrl: { type: String, default: '/index.php/apps/deck' },\n\t\t/**\n\t\t * Buttons in the card's title row on a detail page: `link` links an\n\t\t * existing Deck card, `create` makes a new one linked to the object.\n\t\t * In the order given; none by default.\n\t\t */\n\t\theaderActions: { type: Array, default: () => [] },\n\t\t/** Label of the `link` button. */\n\t\tlinkLabel: { type: String, default: () => t('nextcloud-vue', 'Link an existing card') },\n\t\t/** Label of the `create` button. */\n\t\tcreateLabel: { type: String, default: () => t('nextcloud-vue', 'New card') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tcards: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t\tactionError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The title-row buttons to draw: only on a detail page with an\n\t\t * object, only the known ones, in the order given.\n\t\t *\n\t\t * @return {Array<string>}\n\t\t */\n\t\tshownHeaderActions() {\n\t\t\tif (this.surface !== 'detail-page' || !this.objectId || !Array.isArray(this.headerActions)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.headerActions.filter((action, index, all) => ['create', 'link'].includes(action) && all.indexOf(action) === index)\n\t\t},\n\n\t\tcardHeaderTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\t/**\n\t\t * Cards grouped by stack for both the mini-kanban (detail-page)\n\t\t * and the stack-distribution list (dashboard surfaces).\n\t\t *\n\t\t * @return {Array<{key: string, label: string, cards: Array}>}\n\t\t */\n\t\tcolumns() {\n\t\t\tconst groups = new Map()\n\t\t\tfor (const card of this.cards) {\n\t\t\t\tconst stackId = card.stackId ?? card.stack?.id ?? 'unstacked'\n\t\t\t\tconst stackLabel = card.stackTitle\n\t\t\t\t\t?? card.stack?.title\n\t\t\t\t\t?? (stackId === 'unstacked'\n\t\t\t\t\t\t? t('nextcloud-vue', 'No stack')\n\t\t\t\t\t\t: t('nextcloud-vue', 'Stack {n}', { n: stackId }))\n\t\t\t\tconst key = String(stackId)\n\t\t\t\tif (!groups.has(key)) {\n\t\t\t\t\tgroups.set(key, { key, label: stackLabel, cards: [] })\n\t\t\t\t}\n\t\t\t\tgroups.get(key).cards.push(card)\n\t\t\t}\n\t\t\treturn Array.from(groups.values())\n\t\t},\n\n\t\t/**\n\t\t * Up to three columns for the mini-kanban view on `detail-page`.\n\t\t *\n\t\t * Per AD-2 (design.md): when the linked card has its own stack\n\t\t * we always include that stack; otherwise the first three stacks\n\t\t * by first-seen order are surfaced.\n\t\t *\n\t\t * @return {Array<{key: string, label: string, cards: Array}>}\n\t\t */\n\t\tminiColumns() {\n\t\t\treturn this.columns.slice(0, 3)\n\t\t},\n\n\t\tstackDistribution() {\n\t\t\treturn this.columns.map((col) => ({\n\t\t\t\tkey: col.key,\n\t\t\t\tlabel: col.label,\n\t\t\t\tcount: col.cards.length,\n\t\t\t}))\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.cards.length\n\t\t\tconst stackCount = this.columns.length\n\t\t\tif (stackCount <= 1) {\n\t\t\t\treturn n('nextcloud-vue', '{count} card', '{count} cards', total, { count: total })\n\t\t\t}\n\t\t\tconst cardFragment = n('nextcloud-vue', '{count} card', '{count} cards', total, { count: total })\n\t\t\tconst stacksFragment = n('nextcloud-vue', 'across {count} stack', 'across {count} stacks', stackCount, { count: stackCount })\n\t\t\treturn `${cardFragment} ${stacksFragment}`\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.cards.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.cards].sort((a, b) => {\n\t\t\t\tconst ta = Date.parse(a.linkedAt ?? a.lastActivity ?? '') || 0\n\t\t\t\tconst tb = Date.parse(b.linkedAt ?? b.lastActivity ?? '') || 0\n\t\t\t\treturn tb - ta\n\t\t\t})\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/** @return {string} The object's Deck endpoint the link and create flows post to. */\n\t\tdeckEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/deck`\n\t\t},\n\n\t\t/**\n\t\t * Link the picked card, then read the list again.\n\t\t *\n\t\t * @param {object} payload `{ cardId }` from the picker.\n\t\t */\n\t\tasync onLink(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\tawait this.post(this.deckEndpoint(), payload, t('nextcloud-vue', 'Could not link card.'))\n\t\t},\n\n\t\t/**\n\t\t * Create the card linked to the object, then read the list again.\n\t\t *\n\t\t * @param {object} payload `{ boardId, stackId, title, ... }` from the form.\n\t\t */\n\t\tasync onCreate(payload) {\n\t\t\tthis.createOpen = false\n\t\t\tawait this.post(`${this.deckEndpoint()}/new`, payload, t('nextcloud-vue', 'Could not create card.'))\n\t\t},\n\n\t\t/**\n\t\t * POST one flow's payload and reload on success.\n\t\t *\n\t\t * @param {string} url The endpoint.\n\t\t * @param {object} payload The body.\n\t\t * @param {string} failure The sentence shown when it fails.\n\t\t */\n\t\tasync post(url, payload, failure) {\n\t\t\tthis.actionError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchList()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.actionError = t('nextcloud-vue', 'This card is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.actionError = failure\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tthis.actionError = failure\n\t\t\t}\n\t\t},\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tcardKey(card) {\n\t\t\treturn card.cardId ?? card.id ?? ''\n\t\t},\n\n\t\tcardTitle(card) {\n\t\t\treturn card.cardTitle ?? card.title ?? this.cardKey(card)\n\t\t},\n\n\t\tcardUrl(card) {\n\t\t\tif (card.url && safeHref(card.url) !== '#') {\n\t\t\t\treturn card.url\n\t\t\t}\n\t\t\tconst boardId = card.boardId ?? card.board?.id ?? ''\n\t\t\tconst cardId = card.cardId ?? card.id ?? ''\n\t\t\tif (boardId && cardId) {\n\t\t\t\treturn `/index.php/apps/deck/board/${boardId}/card/${cardId}`\n\t\t\t}\n\t\t\treturn this.deckAppUrl\n\t\t},\n\n\t\tstackTitle(card) {\n\t\t\treturn card.stackTitle ?? card.stack?.title ?? ''\n\t\t},\n\n\t\tisLinked(card) {\n\t\t\tif (!this.value) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn String(this.cardKey(card)) === String(this.value)\n\t\t},\n\n\t\tchipSubtitle(card) {\n\t\t\treturn this.stackTitle(card) || this.cardTitle(card)\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { 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.cards = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.cards = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.cards = []\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnDeckCard] failed to fetch cards', err)\n\t\t\t\tthis.cards = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (!this.value || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnDeckCard] failed to fetch single card', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-deck-card__action-error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-deck-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-deck-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-deck-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-deck-card__distribution {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-deck-card__distribution-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-deck-card__distribution-count {\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-deck-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-deck-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-deck-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-deck-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-deck-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-deck-card__chip-stack {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n.cn-deck-card__kanban {\n\tdisplay: flex;\n\tgap: 8px;\n\talign-items: flex-start;\n}\n\n.cn-deck-card__column {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 6px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-deck-card__column-header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 4px;\n}\n\n.cn-deck-card__column-title {\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__column-count {\n\tfont-size: 0.7em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-deck-card__column-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n}\n\n.cn-deck-card__row {\n\tpadding: 4px 6px;\n\tborder-radius: 4px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tfont-size: 0.8em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__row--highlight {\n\tborder-color: var(--color-primary-element, #21468B);\n\tbackground: var(--color-primary-element-light, var(--color-background-darker));\n\tfont-weight: 600;\n}\n\n.cn-deck-card__title {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-deck-card__title:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDeckCardCreate","CnDeckCardPicker","CnDetailCard","t","n"],"mappings":"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"}
1
+ {"version":3,"file":"CnDeckCard.vue2.js","sources":["../../../../../src/integrations/builtin/deck/CnDeckCard.vue"],"sourcesContent":["<!--\n CnDeckCard — bespoke surface-aware widget for the `deck` integration.\n\n Replaces the generic CnIntegrationCard for the `deck` leaf. Branches on\n `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N cards across M stacks\";\n secondary line names the most recent card.\n - detail-page : mini three-column kanban view of\n the linked card's board with the linked card highlighted in its\n current stack (per design.md AD-2).\n - single-entity : chip with card title + stack name\n (referenceType: 'deck').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnDeckTab; for `single-entity` the optional `value` prop addresses a\n single card by id (matching CnIntegrationCard's fetchSingle contract).\n\n See `openregister/openspec/changes/integration-deck/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback),\n AD-2 (mini-kanban on detail-page).\n-->\n<template>\n\t<CnDetailCard :title=\"cardHeaderTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<!-- `headerActions`: the Deck tab's link and create flows in the title row (detail page). -->\n\t\t<template v-if=\"shownHeaderActions.length > 0\" #actions>\n\t\t\t<NcButton\n\t\t\t\tv-for=\"action in shownHeaderActions\"\n\t\t\t\t:key=\"action\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:data-testid=\"`cn-deck-card-${action}`\"\n\t\t\t\t@click.stop=\"action === 'create' ? (createOpen = true) : (pickerOpen = true)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus v-if=\"action === 'create'\" :size=\"20\" />\n\t\t\t\t\t<LinkVariant v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ action === 'create' ? createLabel : linkLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span v-if=\"entity\" class=\"cn-deck-card__chip\" :title=\"chipSubtitle(entity)\">\n\t\t\t\t<ViewColumnOutline :size=\"14\" />\n\t\t\t\t<a\n\t\t\t\t\t:href=\"cardUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ cardTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"stackTitle(entity)\" class=\"cn-deck-card__chip-stack\">\n\t\t\t\t\t· {{ stackTitle(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-deck-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: headline + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"cards.length === 0\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-deck-card__headline\">\n\t\t\t\t<div class=\"cn-deck-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<ul v-if=\"stackDistribution.length > 0\" class=\"cn-deck-card__distribution\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"bucket in stackDistribution\"\n\t\t\t\t\t\t:key=\"bucket.key\"\n\t\t\t\t\t\tclass=\"cn-deck-card__distribution-row\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__distribution-label\">{{ bucket.label }}</span>\n\t\t\t\t\t\t<span class=\"cn-deck-card__distribution-count\">{{ bucket.count }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-deck-card__headline-recent\">\n\t\t\t\t\t<ViewColumnOutline :size=\"14\" />\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"cardUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ cardTitle(mostRecent) }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: mini-kanban -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"cards.length === 0\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<!-- The board look draws each linked card as a ruled row: its title,\n\t\t\t one meta line (board, list, assignees) and its first label at\n\t\t\t the end, then a link to Deck. -->\n\t\t\t<div v-else-if=\"isBoard\" class=\"cn-deck-card__rows\">\n\t\t\t\t<ul class=\"cn-deck-card__row-list\">\n\t\t\t\t\t<li v-for=\"card in cards\"\n\t\t\t\t\t\t:key=\"cardKey(card)\"\n\t\t\t\t\t\tclass=\"cn-deck-card__row\"\n\t\t\t\t\t\tdata-testid=\"cn-deck-card-row\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__row-main\">\n\t\t\t\t\t\t\t<a class=\"cn-deck-card__row-title\"\n\t\t\t\t\t\t\t\t:href=\"cardUrl(card)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\">{{ cardTitle(card) }}</a>\n\t\t\t\t\t\t\t<span class=\"cn-deck-card__row-meta\" data-testid=\"cn-deck-card-meta\">{{ boardMetaOf(card) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"firstLabel(card)\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--purple\"\n\t\t\t\t\t\t\tdata-testid=\"cn-deck-card-label\">{{ firstLabel(card) }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<a class=\"cn-deck-card__open\"\n\t\t\t\t\t:href=\"deckAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\tdata-testid=\"cn-deck-card-open\">{{ openDeckLabel }}</a>\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-deck-card__kanban\">\n\t\t\t\t<section\n\t\t\t\t\tv-for=\"stack in miniColumns\"\n\t\t\t\t\t:key=\"stack.key\"\n\t\t\t\t\tclass=\"cn-deck-card__column\">\n\t\t\t\t\t<header class=\"cn-deck-card__column-header\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__column-title\">{{ stack.label }}</span>\n\t\t\t\t\t\t<span class=\"cn-deck-card__column-count\">{{ stack.cards.length }}</span>\n\t\t\t\t\t</header>\n\t\t\t\t\t<ul class=\"cn-deck-card__column-list\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"card in stack.cards\"\n\t\t\t\t\t\t\t:key=\"cardKey(card)\"\n\t\t\t\t\t\t\tclass=\"cn-deck-card__row\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-deck-card__row--highlight': isLinked(card) }\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t:href=\"cardUrl(card)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\t\tclass=\"cn-deck-card__title\">{{ cardTitle(card) }}</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</section>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<p v-if=\"actionError\" class=\"cn-deck-card__action-error\" role=\"alert\">\n\t\t\t{{ actionError }}\n\t\t</p>\n\n\t\t<CnDeckCardPicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLink\" />\n\n\t\t<CnDeckCardCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreate\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport ViewColumnOutline from 'vue-material-design-icons/ViewColumnOutline.vue'\nimport CnDeckCardCreate from '../../../components/CnDeckCardCreate/CnDeckCardCreate.vue'\nimport CnDeckCardPicker from '../../../components/CnDeckCardPicker/CnDeckCardPicker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { normalizeLook } from '../../../composables/useLook.js'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { assigneeDisplayName, cardAssignees, cardBoardTitle, cardLabels, cardStackTitle } from './deckCardParts.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\n\n/**\n * CnDeckCard — bespoke surface-aware widget for the `deck` integration.\n *\n * Renders Deck-aware metadata across all four surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnDeckCard',\n\n\tcomponents: { CnDeckCardCreate, CnDeckCardPicker, CnDetailCard, LinkVariant, NcButton, NcLoadingIcon, Plus, ViewColumnOutline },\n\n\tinject: {\n\t\tcnLook: { default: 'nextcloud' },\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'deck'`). */\n\t\tintegrationId: { type: String, default: 'deck' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (card id). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Cards') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => ViewColumnOutline },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No cards linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Deck is currently unavailable.') },\n\t\t/** URL of the NC Deck app entry. */\n\t\tdeckAppUrl: { type: String, default: '/index.php/apps/deck' },\n\t\t/**\n\t\t * Buttons in the card's title row on a detail page: `link` links an\n\t\t * existing Deck card, `create` makes a new one linked to the object.\n\t\t * In the order given; none by default.\n\t\t */\n\t\theaderActions: { type: Array, default: () => [] },\n\t\t/** Label of the `link` button. */\n\t\tlinkLabel: { type: String, default: () => t('nextcloud-vue', 'Link an existing card') },\n\t\t/** Label of the `create` button. */\n\t\tcreateLabel: { type: String, default: () => t('nextcloud-vue', 'New card') },\n\t\t/** Label of the link to Deck under the rows (board look). */\n\t\topenDeckLabel: { type: String, default: () => t('nextcloud-vue', 'Open Deck') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tcards: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t\tactionError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The title-row buttons to draw: only on a detail page with an\n\t\t * object, only the known ones, in the order given.\n\t\t *\n\t\t * @return {Array<string>}\n\t\t */\n\t\tshownHeaderActions() {\n\t\t\tif (this.surface !== 'detail-page' || !this.objectId || !Array.isArray(this.headerActions)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.headerActions.filter((action, index, all) => ['create', 'link'].includes(action) && all.indexOf(action) === index)\n\t\t},\n\n\t\t/** @return {boolean} The board look draws ruled rows instead of the mini-kanban. */\n\t\tisBoard() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\tcardHeaderTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\t/**\n\t\t * Cards grouped by stack for both the mini-kanban (detail-page)\n\t\t * and the stack-distribution list (dashboard surfaces).\n\t\t *\n\t\t * @return {Array<{key: string, label: string, cards: Array}>}\n\t\t */\n\t\tcolumns() {\n\t\t\tconst groups = new Map()\n\t\t\tfor (const card of this.cards) {\n\t\t\t\tconst stackId = card.stackId ?? card.stack?.id ?? 'unstacked'\n\t\t\t\tconst stackLabel = card.stackTitle\n\t\t\t\t\t?? card.stack?.title\n\t\t\t\t\t?? (stackId === 'unstacked'\n\t\t\t\t\t\t? t('nextcloud-vue', 'No stack')\n\t\t\t\t\t\t: t('nextcloud-vue', 'Stack {n}', { n: stackId }))\n\t\t\t\tconst key = String(stackId)\n\t\t\t\tif (!groups.has(key)) {\n\t\t\t\t\tgroups.set(key, { key, label: stackLabel, cards: [] })\n\t\t\t\t}\n\t\t\t\tgroups.get(key).cards.push(card)\n\t\t\t}\n\t\t\treturn Array.from(groups.values())\n\t\t},\n\n\t\t/**\n\t\t * Up to three columns for the mini-kanban view on `detail-page`.\n\t\t *\n\t\t * Per AD-2 (design.md): when the linked card has its own stack\n\t\t * we always include that stack; otherwise the first three stacks\n\t\t * by first-seen order are surfaced.\n\t\t *\n\t\t * @return {Array<{key: string, label: string, cards: Array}>}\n\t\t */\n\t\tminiColumns() {\n\t\t\treturn this.columns.slice(0, 3)\n\t\t},\n\n\t\tstackDistribution() {\n\t\t\treturn this.columns.map((col) => ({\n\t\t\t\tkey: col.key,\n\t\t\t\tlabel: col.label,\n\t\t\t\tcount: col.cards.length,\n\t\t\t}))\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.cards.length\n\t\t\tconst stackCount = this.columns.length\n\t\t\tif (stackCount <= 1) {\n\t\t\t\treturn n('nextcloud-vue', '{count} card', '{count} cards', total, { count: total })\n\t\t\t}\n\t\t\tconst cardFragment = n('nextcloud-vue', '{count} card', '{count} cards', total, { count: total })\n\t\t\tconst stacksFragment = n('nextcloud-vue', 'across {count} stack', 'across {count} stacks', stackCount, { count: stackCount })\n\t\t\treturn `${cardFragment} ${stacksFragment}`\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.cards.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.cards].sort((a, b) => {\n\t\t\t\tconst ta = Date.parse(a.linkedAt ?? a.lastActivity ?? '') || 0\n\t\t\t\tconst tb = Date.parse(b.linkedAt ?? b.lastActivity ?? '') || 0\n\t\t\t\treturn tb - ta\n\t\t\t})\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A card's meta line in the board look: its board, its list and its\n\t\t * assignees, separated by middots.\n\t\t *\n\t\t * @param {object} card The card row.\n\t\t * @return {string}\n\t\t */\n\t\tboardMetaOf(card) {\n\t\t\tconst board = cardBoardTitle(card)\n\t\t\tconst stack = cardStackTitle(card)\n\t\t\treturn [\n\t\t\t\tboard ? t('nextcloud-vue', 'Board {name}', { name: board }) : '',\n\t\t\t\tstack ? t('nextcloud-vue', 'list {name}', { name: stack }) : '',\n\t\t\t\t...cardAssignees(card).map(assigneeDisplayName),\n\t\t\t].filter(Boolean).join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * @param {object} card The card row.\n\t\t * @return {string} Its first label's title, or ''.\n\t\t */\n\t\tfirstLabel(card) {\n\t\t\tconst label = cardLabels(card)[0]\n\t\t\treturn label ? String(label.title ?? label.name ?? '') : ''\n\t\t},\n\n\t\t/** @return {string} The object's Deck endpoint the link and create flows post to. */\n\t\tdeckEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/deck`\n\t\t},\n\n\t\t/**\n\t\t * Link the picked card, then read the list again.\n\t\t *\n\t\t * @param {object} payload `{ cardId }` from the picker.\n\t\t */\n\t\tasync onLink(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\tawait this.post(this.deckEndpoint(), payload, t('nextcloud-vue', 'Could not link card.'))\n\t\t},\n\n\t\t/**\n\t\t * Create the card linked to the object, then read the list again.\n\t\t *\n\t\t * @param {object} payload `{ boardId, stackId, title, ... }` from the form.\n\t\t */\n\t\tasync onCreate(payload) {\n\t\t\tthis.createOpen = false\n\t\t\tawait this.post(`${this.deckEndpoint()}/new`, payload, t('nextcloud-vue', 'Could not create card.'))\n\t\t},\n\n\t\t/**\n\t\t * POST one flow's payload and reload on success.\n\t\t *\n\t\t * @param {string} url The endpoint.\n\t\t * @param {object} payload The body.\n\t\t * @param {string} failure The sentence shown when it fails.\n\t\t */\n\t\tasync post(url, payload, failure) {\n\t\t\tthis.actionError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchList()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.actionError = t('nextcloud-vue', 'This card is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.actionError = failure\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tthis.actionError = failure\n\t\t\t}\n\t\t},\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tcardKey(card) {\n\t\t\treturn card.cardId ?? card.id ?? ''\n\t\t},\n\n\t\tcardTitle(card) {\n\t\t\treturn card.cardTitle ?? card.title ?? this.cardKey(card)\n\t\t},\n\n\t\tcardUrl(card) {\n\t\t\tif (card.url && safeHref(card.url) !== '#') {\n\t\t\t\treturn card.url\n\t\t\t}\n\t\t\tconst boardId = card.boardId ?? card.board?.id ?? ''\n\t\t\tconst cardId = card.cardId ?? card.id ?? ''\n\t\t\tif (boardId && cardId) {\n\t\t\t\treturn `/index.php/apps/deck/board/${boardId}/card/${cardId}`\n\t\t\t}\n\t\t\treturn this.deckAppUrl\n\t\t},\n\n\t\tstackTitle(card) {\n\t\t\treturn card.stackTitle ?? card.stack?.title ?? ''\n\t\t},\n\n\t\tisLinked(card) {\n\t\t\tif (!this.value) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn String(this.cardKey(card)) === String(this.value)\n\t\t},\n\n\t\tchipSubtitle(card) {\n\t\t\treturn this.stackTitle(card) || this.cardTitle(card)\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { 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.cards = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.cards = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.cards = []\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnDeckCard] failed to fetch cards', err)\n\t\t\t\tthis.cards = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (!this.value || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnDeckCard] failed to fetch single card', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-deck-card__action-error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-deck-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-deck-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-deck-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-deck-card__distribution {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-deck-card__distribution-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-deck-card__distribution-count {\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-deck-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-deck-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-deck-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-deck-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-deck-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-deck-card__chip-stack {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n.cn-deck-card__kanban {\n\tdisplay: flex;\n\tgap: 8px;\n\talign-items: flex-start;\n}\n\n.cn-deck-card__column {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 6px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-deck-card__column-header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 4px;\n}\n\n.cn-deck-card__column-title {\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__column-count {\n\tfont-size: 0.7em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-deck-card__column-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n}\n\n.cn-deck-card__row {\n\tpadding: 4px 6px;\n\tborder-radius: 4px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tfont-size: 0.8em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__row--highlight {\n\tborder-color: var(--color-primary-element, #21468B);\n\tbackground: var(--color-primary-element-light, var(--color-background-darker));\n\tfont-weight: 600;\n}\n\n.cn-deck-card__title {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-deck-card__title:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["CnDeckCardCreate","CnDeckCardPicker","CnDetailCard","t","n"],"mappings":"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"}
@@ -44,14 +44,31 @@ const _hoisted_15 = {
44
44
  };
45
45
  const _hoisted_16 = {
46
46
  key: 2,
47
+ class: "cn-deck-card__rows"
48
+ };
49
+ const _hoisted_17 = { class: "cn-deck-card__row-list" };
50
+ const _hoisted_18 = { class: "cn-deck-card__row-main" };
51
+ const _hoisted_19 = ["href"];
52
+ const _hoisted_20 = {
53
+ class: "cn-deck-card__row-meta",
54
+ "data-testid": "cn-deck-card-meta"
55
+ };
56
+ const _hoisted_21 = {
57
+ key: 0,
58
+ class: "cn-status-badge cn-status-badge--purple",
59
+ "data-testid": "cn-deck-card-label"
60
+ };
61
+ const _hoisted_22 = ["href"];
62
+ const _hoisted_23 = {
63
+ key: 3,
47
64
  class: "cn-deck-card__kanban"
48
65
  };
49
- const _hoisted_17 = { class: "cn-deck-card__column-header" };
50
- const _hoisted_18 = { class: "cn-deck-card__column-title" };
51
- const _hoisted_19 = { class: "cn-deck-card__column-count" };
52
- const _hoisted_20 = { class: "cn-deck-card__column-list" };
53
- const _hoisted_21 = ["href"];
54
- const _hoisted_22 = {
66
+ const _hoisted_24 = { class: "cn-deck-card__column-header" };
67
+ const _hoisted_25 = { class: "cn-deck-card__column-title" };
68
+ const _hoisted_26 = { class: "cn-deck-card__column-count" };
69
+ const _hoisted_27 = { class: "cn-deck-card__column-list" };
70
+ const _hoisted_28 = ["href"];
71
+ const _hoisted_29 = {
55
72
  key: 4,
56
73
  class: "cn-deck-card__action-error",
57
74
  role: "alert"
@@ -135,37 +152,69 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
135
152
  ? (openBlock(), createElementBlock("div", _hoisted_14, toDisplayString($data.degraded), 1 /* TEXT */))
136
153
  : ($data.cards.length === 0)
137
154
  ? (openBlock(), createElementBlock("div", _hoisted_15, toDisplayString($props.emptyLabel), 1 /* TEXT */))
138
- : (openBlock(), createElementBlock("div", _hoisted_16, [
139
- (openBlock(true), createElementBlock(Fragment, null, renderList($options.miniColumns, (stack) => {
140
- return (openBlock(), createElementBlock("section", {
141
- key: stack.key,
142
- class: "cn-deck-card__column"
143
- }, [
144
- createElementVNode("header", _hoisted_17, [
145
- createElementVNode("span", _hoisted_18, toDisplayString(stack.label), 1 /* TEXT */),
146
- createElementVNode("span", _hoisted_19, toDisplayString(stack.cards.length), 1 /* TEXT */)
147
- ]),
148
- createElementVNode("ul", _hoisted_20, [
149
- (openBlock(true), createElementBlock(Fragment, null, renderList(stack.cards, (card) => {
150
- return (openBlock(), createElementBlock("li", {
151
- key: $options.cardKey(card),
152
- class: normalizeClass(["cn-deck-card__row", { 'cn-deck-card__row--highlight': $options.isLinked(card) }])
153
- }, [
155
+ : ($options.isBoard)
156
+ ? (openBlock(), createElementBlock("div", _hoisted_16, [
157
+ createElementVNode("ul", _hoisted_17, [
158
+ (openBlock(true), createElementBlock(Fragment, null, renderList($data.cards, (card) => {
159
+ return (openBlock(), createElementBlock("li", {
160
+ key: $options.cardKey(card),
161
+ class: "cn-deck-card__row",
162
+ "data-testid": "cn-deck-card-row"
163
+ }, [
164
+ createElementVNode("span", _hoisted_18, [
154
165
  createElementVNode("a", {
166
+ class: "cn-deck-card__row-title",
155
167
  href: $options.cardUrl(card),
156
168
  target: "_blank",
157
- rel: "noopener",
158
- class: "cn-deck-card__title"
159
- }, toDisplayString($options.cardTitle(card)), 9 /* TEXT, PROPS */, _hoisted_21)
160
- ], 2 /* CLASS */))
161
- }), 128 /* KEYED_FRAGMENT */))
162
- ])
163
- ]))
164
- }), 128 /* KEYED_FRAGMENT */))
165
- ]))
169
+ rel: "noopener"
170
+ }, toDisplayString($options.cardTitle(card)), 9 /* TEXT, PROPS */, _hoisted_19),
171
+ createElementVNode("span", _hoisted_20, toDisplayString($options.boardMetaOf(card)), 1 /* TEXT */)
172
+ ]),
173
+ ($options.firstLabel(card))
174
+ ? (openBlock(), createElementBlock("span", _hoisted_21, toDisplayString($options.firstLabel(card)), 1 /* TEXT */))
175
+ : createCommentVNode("v-if", true)
176
+ ]))
177
+ }), 128 /* KEYED_FRAGMENT */))
178
+ ]),
179
+ createElementVNode("a", {
180
+ class: "cn-deck-card__open",
181
+ href: $props.deckAppUrl,
182
+ target: "_blank",
183
+ rel: "noopener",
184
+ "data-testid": "cn-deck-card-open"
185
+ }, toDisplayString($props.openDeckLabel), 9 /* TEXT, PROPS */, _hoisted_22)
186
+ ]))
187
+ : (openBlock(), createElementBlock("div", _hoisted_23, [
188
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.miniColumns, (stack) => {
189
+ return (openBlock(), createElementBlock("section", {
190
+ key: stack.key,
191
+ class: "cn-deck-card__column"
192
+ }, [
193
+ createElementVNode("header", _hoisted_24, [
194
+ createElementVNode("span", _hoisted_25, toDisplayString(stack.label), 1 /* TEXT */),
195
+ createElementVNode("span", _hoisted_26, toDisplayString(stack.cards.length), 1 /* TEXT */)
196
+ ]),
197
+ createElementVNode("ul", _hoisted_27, [
198
+ (openBlock(true), createElementBlock(Fragment, null, renderList(stack.cards, (card) => {
199
+ return (openBlock(), createElementBlock("li", {
200
+ key: $options.cardKey(card),
201
+ class: normalizeClass(["cn-deck-card__row", { 'cn-deck-card__row--highlight': $options.isLinked(card) }])
202
+ }, [
203
+ createElementVNode("a", {
204
+ href: $options.cardUrl(card),
205
+ target: "_blank",
206
+ rel: "noopener",
207
+ class: "cn-deck-card__title"
208
+ }, toDisplayString($options.cardTitle(card)), 9 /* TEXT, PROPS */, _hoisted_28)
209
+ ], 2 /* CLASS */))
210
+ }), 128 /* KEYED_FRAGMENT */))
211
+ ])
212
+ ]))
213
+ }), 128 /* KEYED_FRAGMENT */))
214
+ ]))
166
215
  ], 64 /* STABLE_FRAGMENT */)),
167
216
  ($data.actionError)
168
- ? (openBlock(), createElementBlock("p", _hoisted_22, toDisplayString($data.actionError), 1 /* TEXT */))
217
+ ? (openBlock(), createElementBlock("p", _hoisted_29, toDisplayString($data.actionError), 1 /* TEXT */))
169
218
  : createCommentVNode("v-if", true),
170
219
  ($data.pickerOpen)
171
220
  ? (openBlock(), createBlock(_component_CnDeckCardPicker, {
@@ -1 +1 @@
1
- {"version":3,"file":"CnDeckCard.vue3.js","sources":["../../../../../src/integrations/builtin/deck/CnDeckCard.vue?vue&type=template&id=d8cff1c2&lang.js"],"sourcesContent":["<!--\n CnDeckCard — bespoke surface-aware widget for the `deck` integration.\n\n Replaces the generic CnIntegrationCard for the `deck` leaf. Branches on\n `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N cards across M stacks\";\n secondary line names the most recent card.\n - detail-page : mini three-column kanban view of\n the linked card's board with the linked card highlighted in its\n current stack (per design.md AD-2).\n - single-entity : chip with card title + stack name\n (referenceType: 'deck').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnDeckTab; for `single-entity` the optional `value` prop addresses a\n single card by id (matching CnIntegrationCard's fetchSingle contract).\n\n See `openregister/openspec/changes/integration-deck/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback),\n AD-2 (mini-kanban on detail-page).\n-->\n<template>\n\t<CnDetailCard :title=\"cardHeaderTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<!-- `headerActions`: the Deck tab's link and create flows in the title row (detail page). -->\n\t\t<template v-if=\"shownHeaderActions.length > 0\" #actions>\n\t\t\t<NcButton\n\t\t\t\tv-for=\"action in shownHeaderActions\"\n\t\t\t\t:key=\"action\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:data-testid=\"`cn-deck-card-${action}`\"\n\t\t\t\t@click.stop=\"action === 'create' ? (createOpen = true) : (pickerOpen = true)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus v-if=\"action === 'create'\" :size=\"20\" />\n\t\t\t\t\t<LinkVariant v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ action === 'create' ? createLabel : linkLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span v-if=\"entity\" class=\"cn-deck-card__chip\" :title=\"chipSubtitle(entity)\">\n\t\t\t\t<ViewColumnOutline :size=\"14\" />\n\t\t\t\t<a\n\t\t\t\t\t:href=\"cardUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ cardTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"stackTitle(entity)\" class=\"cn-deck-card__chip-stack\">\n\t\t\t\t\t· {{ stackTitle(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-deck-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: headline + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"cards.length === 0\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-deck-card__headline\">\n\t\t\t\t<div class=\"cn-deck-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<ul v-if=\"stackDistribution.length > 0\" class=\"cn-deck-card__distribution\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"bucket in stackDistribution\"\n\t\t\t\t\t\t:key=\"bucket.key\"\n\t\t\t\t\t\tclass=\"cn-deck-card__distribution-row\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__distribution-label\">{{ bucket.label }}</span>\n\t\t\t\t\t\t<span class=\"cn-deck-card__distribution-count\">{{ bucket.count }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-deck-card__headline-recent\">\n\t\t\t\t\t<ViewColumnOutline :size=\"14\" />\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"cardUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ cardTitle(mostRecent) }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: mini-kanban -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"cards.length === 0\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-deck-card__kanban\">\n\t\t\t\t<section\n\t\t\t\t\tv-for=\"stack in miniColumns\"\n\t\t\t\t\t:key=\"stack.key\"\n\t\t\t\t\tclass=\"cn-deck-card__column\">\n\t\t\t\t\t<header class=\"cn-deck-card__column-header\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__column-title\">{{ stack.label }}</span>\n\t\t\t\t\t\t<span class=\"cn-deck-card__column-count\">{{ stack.cards.length }}</span>\n\t\t\t\t\t</header>\n\t\t\t\t\t<ul class=\"cn-deck-card__column-list\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"card in stack.cards\"\n\t\t\t\t\t\t\t:key=\"cardKey(card)\"\n\t\t\t\t\t\t\tclass=\"cn-deck-card__row\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-deck-card__row--highlight': isLinked(card) }\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t:href=\"cardUrl(card)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\t\tclass=\"cn-deck-card__title\">{{ cardTitle(card) }}</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</section>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<p v-if=\"actionError\" class=\"cn-deck-card__action-error\" role=\"alert\">\n\t\t\t{{ actionError }}\n\t\t</p>\n\n\t\t<CnDeckCardPicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLink\" />\n\n\t\t<CnDeckCardCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreate\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport ViewColumnOutline from 'vue-material-design-icons/ViewColumnOutline.vue'\nimport CnDeckCardCreate from '../../../components/CnDeckCardCreate/CnDeckCardCreate.vue'\nimport CnDeckCardPicker from '../../../components/CnDeckCardPicker/CnDeckCardPicker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\n\n/**\n * CnDeckCard — bespoke surface-aware widget for the `deck` integration.\n *\n * Renders Deck-aware metadata across all four surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnDeckCard',\n\n\tcomponents: { CnDeckCardCreate, CnDeckCardPicker, CnDetailCard, LinkVariant, NcButton, NcLoadingIcon, Plus, ViewColumnOutline },\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'deck'`). */\n\t\tintegrationId: { type: String, default: 'deck' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (card id). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Cards') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => ViewColumnOutline },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No cards linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Deck is currently unavailable.') },\n\t\t/** URL of the NC Deck app entry. */\n\t\tdeckAppUrl: { type: String, default: '/index.php/apps/deck' },\n\t\t/**\n\t\t * Buttons in the card's title row on a detail page: `link` links an\n\t\t * existing Deck card, `create` makes a new one linked to the object.\n\t\t * In the order given; none by default.\n\t\t */\n\t\theaderActions: { type: Array, default: () => [] },\n\t\t/** Label of the `link` button. */\n\t\tlinkLabel: { type: String, default: () => t('nextcloud-vue', 'Link an existing card') },\n\t\t/** Label of the `create` button. */\n\t\tcreateLabel: { type: String, default: () => t('nextcloud-vue', 'New card') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tcards: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t\tactionError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The title-row buttons to draw: only on a detail page with an\n\t\t * object, only the known ones, in the order given.\n\t\t *\n\t\t * @return {Array<string>}\n\t\t */\n\t\tshownHeaderActions() {\n\t\t\tif (this.surface !== 'detail-page' || !this.objectId || !Array.isArray(this.headerActions)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.headerActions.filter((action, index, all) => ['create', 'link'].includes(action) && all.indexOf(action) === index)\n\t\t},\n\n\t\tcardHeaderTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\t/**\n\t\t * Cards grouped by stack for both the mini-kanban (detail-page)\n\t\t * and the stack-distribution list (dashboard surfaces).\n\t\t *\n\t\t * @return {Array<{key: string, label: string, cards: Array}>}\n\t\t */\n\t\tcolumns() {\n\t\t\tconst groups = new Map()\n\t\t\tfor (const card of this.cards) {\n\t\t\t\tconst stackId = card.stackId ?? card.stack?.id ?? 'unstacked'\n\t\t\t\tconst stackLabel = card.stackTitle\n\t\t\t\t\t?? card.stack?.title\n\t\t\t\t\t?? (stackId === 'unstacked'\n\t\t\t\t\t\t? t('nextcloud-vue', 'No stack')\n\t\t\t\t\t\t: t('nextcloud-vue', 'Stack {n}', { n: stackId }))\n\t\t\t\tconst key = String(stackId)\n\t\t\t\tif (!groups.has(key)) {\n\t\t\t\t\tgroups.set(key, { key, label: stackLabel, cards: [] })\n\t\t\t\t}\n\t\t\t\tgroups.get(key).cards.push(card)\n\t\t\t}\n\t\t\treturn Array.from(groups.values())\n\t\t},\n\n\t\t/**\n\t\t * Up to three columns for the mini-kanban view on `detail-page`.\n\t\t *\n\t\t * Per AD-2 (design.md): when the linked card has its own stack\n\t\t * we always include that stack; otherwise the first three stacks\n\t\t * by first-seen order are surfaced.\n\t\t *\n\t\t * @return {Array<{key: string, label: string, cards: Array}>}\n\t\t */\n\t\tminiColumns() {\n\t\t\treturn this.columns.slice(0, 3)\n\t\t},\n\n\t\tstackDistribution() {\n\t\t\treturn this.columns.map((col) => ({\n\t\t\t\tkey: col.key,\n\t\t\t\tlabel: col.label,\n\t\t\t\tcount: col.cards.length,\n\t\t\t}))\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.cards.length\n\t\t\tconst stackCount = this.columns.length\n\t\t\tif (stackCount <= 1) {\n\t\t\t\treturn n('nextcloud-vue', '{count} card', '{count} cards', total, { count: total })\n\t\t\t}\n\t\t\tconst cardFragment = n('nextcloud-vue', '{count} card', '{count} cards', total, { count: total })\n\t\t\tconst stacksFragment = n('nextcloud-vue', 'across {count} stack', 'across {count} stacks', stackCount, { count: stackCount })\n\t\t\treturn `${cardFragment} ${stacksFragment}`\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.cards.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.cards].sort((a, b) => {\n\t\t\t\tconst ta = Date.parse(a.linkedAt ?? a.lastActivity ?? '') || 0\n\t\t\t\tconst tb = Date.parse(b.linkedAt ?? b.lastActivity ?? '') || 0\n\t\t\t\treturn tb - ta\n\t\t\t})\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/** @return {string} The object's Deck endpoint the link and create flows post to. */\n\t\tdeckEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/deck`\n\t\t},\n\n\t\t/**\n\t\t * Link the picked card, then read the list again.\n\t\t *\n\t\t * @param {object} payload `{ cardId }` from the picker.\n\t\t */\n\t\tasync onLink(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\tawait this.post(this.deckEndpoint(), payload, t('nextcloud-vue', 'Could not link card.'))\n\t\t},\n\n\t\t/**\n\t\t * Create the card linked to the object, then read the list again.\n\t\t *\n\t\t * @param {object} payload `{ boardId, stackId, title, ... }` from the form.\n\t\t */\n\t\tasync onCreate(payload) {\n\t\t\tthis.createOpen = false\n\t\t\tawait this.post(`${this.deckEndpoint()}/new`, payload, t('nextcloud-vue', 'Could not create card.'))\n\t\t},\n\n\t\t/**\n\t\t * POST one flow's payload and reload on success.\n\t\t *\n\t\t * @param {string} url The endpoint.\n\t\t * @param {object} payload The body.\n\t\t * @param {string} failure The sentence shown when it fails.\n\t\t */\n\t\tasync post(url, payload, failure) {\n\t\t\tthis.actionError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchList()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.actionError = t('nextcloud-vue', 'This card is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.actionError = failure\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tthis.actionError = failure\n\t\t\t}\n\t\t},\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tcardKey(card) {\n\t\t\treturn card.cardId ?? card.id ?? ''\n\t\t},\n\n\t\tcardTitle(card) {\n\t\t\treturn card.cardTitle ?? card.title ?? this.cardKey(card)\n\t\t},\n\n\t\tcardUrl(card) {\n\t\t\tif (card.url && safeHref(card.url) !== '#') {\n\t\t\t\treturn card.url\n\t\t\t}\n\t\t\tconst boardId = card.boardId ?? card.board?.id ?? ''\n\t\t\tconst cardId = card.cardId ?? card.id ?? ''\n\t\t\tif (boardId && cardId) {\n\t\t\t\treturn `/index.php/apps/deck/board/${boardId}/card/${cardId}`\n\t\t\t}\n\t\t\treturn this.deckAppUrl\n\t\t},\n\n\t\tstackTitle(card) {\n\t\t\treturn card.stackTitle ?? card.stack?.title ?? ''\n\t\t},\n\n\t\tisLinked(card) {\n\t\t\tif (!this.value) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn String(this.cardKey(card)) === String(this.value)\n\t\t},\n\n\t\tchipSubtitle(card) {\n\t\t\treturn this.stackTitle(card) || this.cardTitle(card)\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { 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.cards = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.cards = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.cards = []\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnDeckCard] failed to fetch cards', err)\n\t\t\t\tthis.cards = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (!this.value || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnDeckCard] failed to fetch single card', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-deck-card__action-error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-deck-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-deck-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-deck-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-deck-card__distribution {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-deck-card__distribution-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-deck-card__distribution-count {\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-deck-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-deck-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-deck-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-deck-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-deck-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-deck-card__chip-stack {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n.cn-deck-card__kanban {\n\tdisplay: flex;\n\tgap: 8px;\n\talign-items: flex-start;\n}\n\n.cn-deck-card__column {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 6px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-deck-card__column-header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 4px;\n}\n\n.cn-deck-card__column-title {\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__column-count {\n\tfont-size: 0.7em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-deck-card__column-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n}\n\n.cn-deck-card__row {\n\tpadding: 4px 6px;\n\tborder-radius: 4px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tfont-size: 0.8em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__row--highlight {\n\tborder-color: var(--color-primary-element, #21468B);\n\tbackground: var(--color-primary-element-light, var(--color-background-darker));\n\tfont-weight: 600;\n}\n\n.cn-deck-card__title {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-deck-card__title:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_Fragment","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_openBlock","_renderList","_normalizeClass","_withModifiers"],"mappings":"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"}
1
+ {"version":3,"file":"CnDeckCard.vue3.js","sources":["../../../../../src/integrations/builtin/deck/CnDeckCard.vue?vue&type=template&id=68f05db0&lang.js"],"sourcesContent":["<!--\n CnDeckCard — bespoke surface-aware widget for the `deck` integration.\n\n Replaces the generic CnIntegrationCard for the `deck` leaf. Branches on\n `surface` per AD-19:\n - user-dashboard / app-dashboard : headline \"N cards across M stacks\";\n secondary line names the most recent card.\n - detail-page : mini three-column kanban view of\n the linked card's board with the linked card highlighted in its\n current stack (per design.md AD-2).\n - single-entity : chip with card title + stack name\n (referenceType: 'deck').\n\n Pulls rows from the same OR pluggable-integration sub-resource as\n CnDeckTab; for `single-entity` the optional `value` prop addresses a\n single card by id (matching CnIntegrationCard's fetchSingle contract).\n\n See `openregister/openspec/changes/integration-deck/` for the spec\n delta and ADR-019 (registry mechanism), AD-19 (surface fallback),\n AD-2 (mini-kanban on detail-page).\n-->\n<template>\n\t<CnDetailCard :title=\"cardHeaderTitle\" :icon=\"cardIcon\" :collapsible=\"collapsible\">\n\t\t<!-- `headerActions`: the Deck tab's link and create flows in the title row (detail page). -->\n\t\t<template v-if=\"shownHeaderActions.length > 0\" #actions>\n\t\t\t<NcButton\n\t\t\t\tv-for=\"action in shownHeaderActions\"\n\t\t\t\t:key=\"action\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:data-testid=\"`cn-deck-card-${action}`\"\n\t\t\t\t@click.stop=\"action === 'create' ? (createOpen = true) : (pickerOpen = true)\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus v-if=\"action === 'create'\" :size=\"20\" />\n\t\t\t\t\t<LinkVariant v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ action === 'create' ? createLabel : linkLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\n\t\t<!-- single-entity surface: chip -->\n\t\t<template v-else-if=\"surface === 'single-entity'\">\n\t\t\t<span v-if=\"entity\" class=\"cn-deck-card__chip\" :title=\"chipSubtitle(entity)\">\n\t\t\t\t<ViewColumnOutline :size=\"14\" />\n\t\t\t\t<a\n\t\t\t\t\t:href=\"cardUrl(entity)\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\">{{ cardTitle(entity) }}</a>\n\t\t\t\t<span v-if=\"stackTitle(entity)\" class=\"cn-deck-card__chip-stack\">\n\t\t\t\t\t· {{ stackTitle(entity) }}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t\t<span v-else class=\"cn-deck-card__empty\">{{ emptyLabel }}</span>\n\t\t</template>\n\n\t\t<!-- dashboard surfaces: headline + most-recent -->\n\t\t<template v-else-if=\"surface === 'user-dashboard' || surface === 'app-dashboard'\">\n\t\t\t<div v-if=\"degraded\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"cards.length === 0\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-deck-card__headline\">\n\t\t\t\t<div class=\"cn-deck-card__headline-line\">\n\t\t\t\t\t<strong>{{ countHeadline }}</strong>\n\t\t\t\t</div>\n\t\t\t\t<ul v-if=\"stackDistribution.length > 0\" class=\"cn-deck-card__distribution\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"bucket in stackDistribution\"\n\t\t\t\t\t\t:key=\"bucket.key\"\n\t\t\t\t\t\tclass=\"cn-deck-card__distribution-row\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__distribution-label\">{{ bucket.label }}</span>\n\t\t\t\t\t\t<span class=\"cn-deck-card__distribution-count\">{{ bucket.count }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"mostRecent\" class=\"cn-deck-card__headline-recent\">\n\t\t\t\t\t<ViewColumnOutline :size=\"14\" />\n\t\t\t\t\t<a\n\t\t\t\t\t\t:href=\"cardUrl(mostRecent)\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener\">{{ cardTitle(mostRecent) }}</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- detail-page surface: mini-kanban -->\n\t\t<template v-else>\n\t\t\t<div v-if=\"degraded\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ degraded }}\n\t\t\t</div>\n\t\t\t<div v-else-if=\"cards.length === 0\" class=\"cn-deck-card__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</div>\n\t\t\t<!-- The board look draws each linked card as a ruled row: its title,\n\t\t\t one meta line (board, list, assignees) and its first label at\n\t\t\t the end, then a link to Deck. -->\n\t\t\t<div v-else-if=\"isBoard\" class=\"cn-deck-card__rows\">\n\t\t\t\t<ul class=\"cn-deck-card__row-list\">\n\t\t\t\t\t<li v-for=\"card in cards\"\n\t\t\t\t\t\t:key=\"cardKey(card)\"\n\t\t\t\t\t\tclass=\"cn-deck-card__row\"\n\t\t\t\t\t\tdata-testid=\"cn-deck-card-row\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__row-main\">\n\t\t\t\t\t\t\t<a class=\"cn-deck-card__row-title\"\n\t\t\t\t\t\t\t\t:href=\"cardUrl(card)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\">{{ cardTitle(card) }}</a>\n\t\t\t\t\t\t\t<span class=\"cn-deck-card__row-meta\" data-testid=\"cn-deck-card-meta\">{{ boardMetaOf(card) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"firstLabel(card)\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--purple\"\n\t\t\t\t\t\t\tdata-testid=\"cn-deck-card-label\">{{ firstLabel(card) }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<a class=\"cn-deck-card__open\"\n\t\t\t\t\t:href=\"deckAppUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\tdata-testid=\"cn-deck-card-open\">{{ openDeckLabel }}</a>\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-deck-card__kanban\">\n\t\t\t\t<section\n\t\t\t\t\tv-for=\"stack in miniColumns\"\n\t\t\t\t\t:key=\"stack.key\"\n\t\t\t\t\tclass=\"cn-deck-card__column\">\n\t\t\t\t\t<header class=\"cn-deck-card__column-header\">\n\t\t\t\t\t\t<span class=\"cn-deck-card__column-title\">{{ stack.label }}</span>\n\t\t\t\t\t\t<span class=\"cn-deck-card__column-count\">{{ stack.cards.length }}</span>\n\t\t\t\t\t</header>\n\t\t\t\t\t<ul class=\"cn-deck-card__column-list\">\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tv-for=\"card in stack.cards\"\n\t\t\t\t\t\t\t:key=\"cardKey(card)\"\n\t\t\t\t\t\t\tclass=\"cn-deck-card__row\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-deck-card__row--highlight': isLinked(card) }\">\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t:href=\"cardUrl(card)\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener\"\n\t\t\t\t\t\t\t\tclass=\"cn-deck-card__title\">{{ cardTitle(card) }}</a>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</section>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<p v-if=\"actionError\" class=\"cn-deck-card__action-error\" role=\"alert\">\n\t\t\t{{ actionError }}\n\t\t</p>\n\n\t\t<CnDeckCardPicker\n\t\t\tv-if=\"pickerOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"pickerOpen = false\"\n\t\t\t@link=\"onLink\" />\n\n\t\t<CnDeckCardCreate\n\t\t\tv-if=\"createOpen\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@close=\"createOpen = false\"\n\t\t\t@create=\"onCreate\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport LinkVariant from 'vue-material-design-icons/LinkVariant.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport ViewColumnOutline from 'vue-material-design-icons/ViewColumnOutline.vue'\nimport CnDeckCardCreate from '../../../components/CnDeckCardCreate/CnDeckCardCreate.vue'\nimport CnDeckCardPicker from '../../../components/CnDeckCardPicker/CnDeckCardPicker.vue'\nimport CnDetailCard from '../../../components/CnDetailCard/CnDetailCard.vue'\nimport { normalizeLook } from '../../../composables/useLook.js'\nimport { buildHeaders, prefixUrl, safeHref } from '../../../utils/index.js'\nimport { assigneeDisplayName, cardAssignees, cardBoardTitle, cardLabels, cardStackTitle } from './deckCardParts.js'\n\nconst VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity']\n\n/**\n * CnDeckCard — bespoke surface-aware widget for the `deck` integration.\n *\n * Renders Deck-aware metadata across all four surfaces. See the\n * file-level docblock for surface-by-surface behaviour.\n */\nexport default {\n\tname: 'CnDeckCard',\n\n\tcomponents: { CnDeckCardCreate, CnDeckCardPicker, CnDetailCard, LinkVariant, NcButton, NcLoadingIcon, Plus, ViewColumnOutline },\n\n\tinject: {\n\t\tcnLook: { default: 'nextcloud' },\n\t},\n\n\tprops: {\n\t\t/** Stable integration id (forwarded from the registry — always `'deck'`). */\n\t\tintegrationId: { type: String, default: 'deck' },\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface (AD-19). */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (s) => VALID_SURFACES.includes(s),\n\t\t},\n\n\t\t/** Optional single-entity reference (card id). */\n\t\tvalue: { type: [String, Number], default: '' },\n\t\t/** Pre-translated card title. */\n\t\ttitle: { type: String, default: () => t('nextcloud-vue', 'Cards') },\n\t\t/** Optional Material Design Icon component. */\n\t\ticon: { type: Object, default: () => ViewColumnOutline },\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Whether the card body is collapsible. */\n\t\tcollapsible: { type: Boolean, default: true },\n\t\t/** Pre-translated empty-state label. */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'No cards linked yet') },\n\t\t/** Pre-translated unavailable label. */\n\t\tunavailableLabel: { type: String, default: () => t('nextcloud-vue', 'NC Deck is currently unavailable.') },\n\t\t/** URL of the NC Deck app entry. */\n\t\tdeckAppUrl: { type: String, default: '/index.php/apps/deck' },\n\t\t/**\n\t\t * Buttons in the card's title row on a detail page: `link` links an\n\t\t * existing Deck card, `create` makes a new one linked to the object.\n\t\t * In the order given; none by default.\n\t\t */\n\t\theaderActions: { type: Array, default: () => [] },\n\t\t/** Label of the `link` button. */\n\t\tlinkLabel: { type: String, default: () => t('nextcloud-vue', 'Link an existing card') },\n\t\t/** Label of the `create` button. */\n\t\tcreateLabel: { type: String, default: () => t('nextcloud-vue', 'New card') },\n\t\t/** Label of the link to Deck under the rows (board look). */\n\t\topenDeckLabel: { type: String, default: () => t('nextcloud-vue', 'Open Deck') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tcards: [],\n\t\t\tentity: null,\n\t\t\tloading: false,\n\t\t\tdegraded: '',\n\t\t\tpickerOpen: false,\n\t\t\tcreateOpen: false,\n\t\t\tactionError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The title-row buttons to draw: only on a detail page with an\n\t\t * object, only the known ones, in the order given.\n\t\t *\n\t\t * @return {Array<string>}\n\t\t */\n\t\tshownHeaderActions() {\n\t\t\tif (this.surface !== 'detail-page' || !this.objectId || !Array.isArray(this.headerActions)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.headerActions.filter((action, index, all) => ['create', 'link'].includes(action) && all.indexOf(action) === index)\n\t\t},\n\n\t\t/** @return {boolean} The board look draws ruled rows instead of the mini-kanban. */\n\t\tisBoard() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\tcardHeaderTitle() {\n\t\t\treturn this.title || this.integrationId\n\t\t},\n\n\t\tcardIcon() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\t/**\n\t\t * Cards grouped by stack for both the mini-kanban (detail-page)\n\t\t * and the stack-distribution list (dashboard surfaces).\n\t\t *\n\t\t * @return {Array<{key: string, label: string, cards: Array}>}\n\t\t */\n\t\tcolumns() {\n\t\t\tconst groups = new Map()\n\t\t\tfor (const card of this.cards) {\n\t\t\t\tconst stackId = card.stackId ?? card.stack?.id ?? 'unstacked'\n\t\t\t\tconst stackLabel = card.stackTitle\n\t\t\t\t\t?? card.stack?.title\n\t\t\t\t\t?? (stackId === 'unstacked'\n\t\t\t\t\t\t? t('nextcloud-vue', 'No stack')\n\t\t\t\t\t\t: t('nextcloud-vue', 'Stack {n}', { n: stackId }))\n\t\t\t\tconst key = String(stackId)\n\t\t\t\tif (!groups.has(key)) {\n\t\t\t\t\tgroups.set(key, { key, label: stackLabel, cards: [] })\n\t\t\t\t}\n\t\t\t\tgroups.get(key).cards.push(card)\n\t\t\t}\n\t\t\treturn Array.from(groups.values())\n\t\t},\n\n\t\t/**\n\t\t * Up to three columns for the mini-kanban view on `detail-page`.\n\t\t *\n\t\t * Per AD-2 (design.md): when the linked card has its own stack\n\t\t * we always include that stack; otherwise the first three stacks\n\t\t * by first-seen order are surfaced.\n\t\t *\n\t\t * @return {Array<{key: string, label: string, cards: Array}>}\n\t\t */\n\t\tminiColumns() {\n\t\t\treturn this.columns.slice(0, 3)\n\t\t},\n\n\t\tstackDistribution() {\n\t\t\treturn this.columns.map((col) => ({\n\t\t\t\tkey: col.key,\n\t\t\t\tlabel: col.label,\n\t\t\t\tcount: col.cards.length,\n\t\t\t}))\n\t\t},\n\n\t\tcountHeadline() {\n\t\t\tconst total = this.cards.length\n\t\t\tconst stackCount = this.columns.length\n\t\t\tif (stackCount <= 1) {\n\t\t\t\treturn n('nextcloud-vue', '{count} card', '{count} cards', total, { count: total })\n\t\t\t}\n\t\t\tconst cardFragment = n('nextcloud-vue', '{count} card', '{count} cards', total, { count: total })\n\t\t\tconst stacksFragment = n('nextcloud-vue', 'across {count} stack', 'across {count} stacks', stackCount, { count: stackCount })\n\t\t\treturn `${cardFragment} ${stacksFragment}`\n\t\t},\n\n\t\tmostRecent() {\n\t\t\tif (this.cards.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst sorted = [...this.cards].sort((a, b) => {\n\t\t\t\tconst ta = Date.parse(a.linkedAt ?? a.lastActivity ?? '') || 0\n\t\t\t\tconst tb = Date.parse(b.linkedAt ?? b.lastActivity ?? '') || 0\n\t\t\t\treturn tb - ta\n\t\t\t})\n\t\t\treturn sorted[0]\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: { immediate: true, handler() {\n\t\t\tthis.fetch()\n\t\t} },\n\n\t\tsurface() {\n\t\t\tthis.fetch()\n\t\t},\n\n\t\tvalue() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A card's meta line in the board look: its board, its list and its\n\t\t * assignees, separated by middots.\n\t\t *\n\t\t * @param {object} card The card row.\n\t\t * @return {string}\n\t\t */\n\t\tboardMetaOf(card) {\n\t\t\tconst board = cardBoardTitle(card)\n\t\t\tconst stack = cardStackTitle(card)\n\t\t\treturn [\n\t\t\t\tboard ? t('nextcloud-vue', 'Board {name}', { name: board }) : '',\n\t\t\t\tstack ? t('nextcloud-vue', 'list {name}', { name: stack }) : '',\n\t\t\t\t...cardAssignees(card).map(assigneeDisplayName),\n\t\t\t].filter(Boolean).join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * @param {object} card The card row.\n\t\t * @return {string} Its first label's title, or ''.\n\t\t */\n\t\tfirstLabel(card) {\n\t\t\tconst label = cardLabels(card)[0]\n\t\t\treturn label ? String(label.title ?? label.name ?? '') : ''\n\t\t},\n\n\t\t/** @return {string} The object's Deck endpoint the link and create flows post to. */\n\t\tdeckEndpoint() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/deck`\n\t\t},\n\n\t\t/**\n\t\t * Link the picked card, then read the list again.\n\t\t *\n\t\t * @param {object} payload `{ cardId }` from the picker.\n\t\t */\n\t\tasync onLink(payload) {\n\t\t\tthis.pickerOpen = false\n\t\t\tawait this.post(this.deckEndpoint(), payload, t('nextcloud-vue', 'Could not link card.'))\n\t\t},\n\n\t\t/**\n\t\t * Create the card linked to the object, then read the list again.\n\t\t *\n\t\t * @param {object} payload `{ boardId, stackId, title, ... }` from the form.\n\t\t */\n\t\tasync onCreate(payload) {\n\t\t\tthis.createOpen = false\n\t\t\tawait this.post(`${this.deckEndpoint()}/new`, payload, t('nextcloud-vue', 'Could not create card.'))\n\t\t},\n\n\t\t/**\n\t\t * POST one flow's payload and reload on success.\n\t\t *\n\t\t * @param {string} url The endpoint.\n\t\t * @param {object} payload The body.\n\t\t * @param {string} failure The sentence shown when it fails.\n\t\t */\n\t\tasync post(url, payload, failure) {\n\t\t\tthis.actionError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { ...buildHeaders(), 'Content-Type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify(payload),\n\t\t\t\t})\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tawait this.fetchList()\n\t\t\t\t} else if (response.status === 409) {\n\t\t\t\t\tthis.actionError = t('nextcloud-vue', 'This card is already linked.')\n\t\t\t\t} else {\n\t\t\t\t\tthis.actionError = failure\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tthis.actionError = failure\n\t\t\t}\n\t\t},\n\n\t\tbaseUrl() {\n\t\t\treturn `${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/integrations/${this.integrationId}`\n\t\t},\n\n\t\tcardKey(card) {\n\t\t\treturn card.cardId ?? card.id ?? ''\n\t\t},\n\n\t\tcardTitle(card) {\n\t\t\treturn card.cardTitle ?? card.title ?? this.cardKey(card)\n\t\t},\n\n\t\tcardUrl(card) {\n\t\t\tif (card.url && safeHref(card.url) !== '#') {\n\t\t\t\treturn card.url\n\t\t\t}\n\t\t\tconst boardId = card.boardId ?? card.board?.id ?? ''\n\t\t\tconst cardId = card.cardId ?? card.id ?? ''\n\t\t\tif (boardId && cardId) {\n\t\t\t\treturn `/index.php/apps/deck/board/${boardId}/card/${cardId}`\n\t\t\t}\n\t\t\treturn this.deckAppUrl\n\t\t},\n\n\t\tstackTitle(card) {\n\t\t\treturn card.stackTitle ?? card.stack?.title ?? ''\n\t\t},\n\n\t\tisLinked(card) {\n\t\t\tif (!this.value) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn String(this.cardKey(card)) === String(this.value)\n\t\t},\n\n\t\tchipSubtitle(card) {\n\t\t\treturn this.stackTitle(card) || this.cardTitle(card)\n\t\t},\n\n\t\tfetch() {\n\t\t\tif (this.surface === 'single-entity') {\n\t\t\t\tthis.fetchSingle()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.fetchList()\n\t\t},\n\n\t\tasync fetchList() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(this.baseUrl()), { 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.cards = data.results || data.items || (Array.isArray(data) ? data : []) || []\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.cards = []\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.cards = []\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnDeckCard] failed to fetch cards', err)\n\t\t\t\tthis.cards = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchSingle() {\n\t\t\tif (!this.value || !this.register || !this.schema || !this.objectId) {\n\t\t\t\tthis.entity = null\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.degraded = ''\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(`${this.baseUrl()}/${encodeURIComponent(this.value)}`), { headers: buildHeaders() })\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tthis.entity = await response.json()\n\t\t\t\t} else if (response.status === 503) {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t\tthis.degraded = this.unavailableLabel\n\t\t\t\t} else {\n\t\t\t\t\tthis.entity = null\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnDeckCard] failed to fetch single card', err)\n\t\t\t\tthis.entity = null\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-deck-card__action-error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-deck-card__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n\tpadding: 8px 0;\n}\n\n.cn-deck-card__headline {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-deck-card__headline-line {\n\tfont-size: 1.1em;\n\tcolor: var(--color-main-text);\n}\n\n.cn-deck-card__distribution {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-deck-card__distribution-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-deck-card__distribution-count {\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-deck-card__headline-recent {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__headline-recent a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-deck-card__headline-recent a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-deck-card__chip {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 6px;\n\tpadding: 4px 8px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-hover);\n\tfont-size: 0.9em;\n\tmax-width: 100%;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* stylelint-disable-next-line no-descending-specificity */\n.cn-deck-card__chip a {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-deck-card__chip a:hover {\n\ttext-decoration: underline;\n}\n\n.cn-deck-card__chip-stack {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n.cn-deck-card__kanban {\n\tdisplay: flex;\n\tgap: 8px;\n\talign-items: flex-start;\n}\n\n.cn-deck-card__column {\n\tflex: 1;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 6px;\n\tborder-radius: var(--border-radius);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-deck-card__column-header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 4px;\n}\n\n.cn-deck-card__column-title {\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__column-count {\n\tfont-size: 0.7em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-deck-card__column-list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n}\n\n.cn-deck-card__row {\n\tpadding: 4px 6px;\n\tborder-radius: 4px;\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tfont-size: 0.8em;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-deck-card__row--highlight {\n\tborder-color: var(--color-primary-element, #21468B);\n\tbackground: var(--color-primary-element-light, var(--color-background-darker));\n\tfont-weight: 600;\n}\n\n.cn-deck-card__title {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\na.cn-deck-card__title:hover {\n\ttext-decoration: underline;\n}\n</style>\n"],"names":["_createBlock","_Fragment","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_openBlock","_renderList","_normalizeClass","_withModifiers"],"mappings":"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"}
@@ -2,7 +2,7 @@ import script from './CnDeckTab.vue2.js';
2
2
  import { render } from './CnDeckTab.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-d4b5abb2";
5
+ script.__scopeId = "data-v-bf899238";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -9,6 +9,7 @@ import __sfc_main$1 from '../../../components/CnDeckCardCreate/CnDeckCardCreate.
9
9
  import __sfc_main from '../../../components/CnDeckCardPicker/CnDeckCardPicker.vue.js';
10
10
  import __sfc_main$2 from '../../../components/CnStatusBadge/CnStatusBadge.vue.js';
11
11
  import { userLocale } from '../../../utils/userLocale.js';
12
+ import { cardLabels, cardBoardTitle, cardStackTitle, cardAssignees } from './deckCardParts.js';
12
13
  import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
13
14
  import { safeHref } from '../../../utils/safeHref.js';
14
15
 
@@ -207,8 +208,7 @@ var script = {
207
208
  },
208
209
 
209
210
  cardLabels(card) {
210
- const labels = card.labels ?? card.tags ?? [];
211
- return Array.isArray(labels) ? labels : []
211
+ return cardLabels(card)
212
212
  },
213
213
 
214
214
  chipText(label) {
@@ -293,8 +293,8 @@ var script = {
293
293
  * @return {string} board (or board · stack) label, or '' when unknown
294
294
  */
295
295
  boardBadge(card) {
296
- const board = card.boardTitle ?? card.board?.title ?? '';
297
- const stack = card.stackTitle ?? card.stack?.title ?? '';
296
+ const board = cardBoardTitle(card);
297
+ const stack = cardStackTitle(card);
298
298
  if (board && stack) {
299
299
  return `${board} · ${stack}`
300
300
  }
@@ -310,8 +310,7 @@ var script = {
310
310
  * @return {Array} assignee entries
311
311
  */
312
312
  cardAssignees(card) {
313
- const raw = card.assignedUsers ?? card.assignees ?? card.users ?? [];
314
- return Array.isArray(raw) ? raw : []
313
+ return cardAssignees(card)
315
314
  },
316
315
 
317
316
  /**