@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":"CnObjectPartiesWidget.vue3.js","sources":["../../../../src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue?vue&type=template&id=0c4e5c0c&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-object-parties\" data-testid=\"cn-object-parties\">\n\t\t<div v-if=\"canAdd\" class=\"cn-object-parties__manage\">\n\t\t\t<NcButton data-testid=\"cn-object-parties-add\" @click=\"adding = true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ manageWord('add', 'label', t('nextcloud-vue', 'Add a party')) }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcNoteCard\n\t\t\tv-if=\"manageError\"\n\t\t\ttype=\"error\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-object-parties-manage-error\">\n\t\t\t{{ manageError }}\n\t\t</NcNoteCard>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"24\" />\n\n\t\t<NcEmptyContent\n\t\t\tv-else-if=\"failed\"\n\t\t\t:name=\"label('failed')\"\n\t\t\t:description=\"label('failedDetail')\"\n\t\t\tdata-testid=\"cn-object-parties-failed\" />\n\n\t\t<div\n\t\t\tv-else-if=\"isPrimaryPresentation\"\n\t\t\tclass=\"cn-object-parties__main-card\"\n\t\t\tdata-testid=\"cn-object-parties-main-card\">\n\t\t\t<div\n\t\t\t\tv-if=\"mainParty\"\n\t\t\t\tclass=\"cn-object-parties__main\"\n\t\t\t\t:data-party=\"mainParty.partyUuid\"\n\t\t\t\tdata-testid=\"cn-object-parties-main\">\n\t\t\t\t<span class=\"cn-object-parties__main-initials\" aria-hidden=\"true\" data-testid=\"cn-object-parties-main-initials\">{{ initialsOf(nameOf(mainParty)) }}</span>\n\t\t\t\t<span class=\"cn-object-parties__main-text\">\n\t\t\t\t\t<strong class=\"cn-object-parties__main-name\" data-testid=\"cn-object-parties-main-name\">{{ nameOf(mainParty) }}</strong>\n\t\t\t\t\t<span v-if=\"mainRole\" class=\"cn-object-parties__muted cn-object-parties__main-role\" data-testid=\"cn-object-parties-main-role\">{{ mainRole }}</span>\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<span v-else class=\"cn-object-parties__muted\" data-testid=\"cn-object-parties-main-none\">{{ label('noPrimary') }}</span>\n\t\t\t<a\n\t\t\t\tv-if=\"mainParty && mainParty.email\"\n\t\t\t\tclass=\"cn-object-parties__main-email\"\n\t\t\t\t:href=\"`mailto:${mainParty.email}`\"\n\t\t\t\tdata-testid=\"cn-object-parties-main-email\">\n\t\t\t\t<EmailOutline :size=\"16\" aria-hidden=\"true\" />{{ mainParty.email }}</a>\n\t\t\t<a\n\t\t\t\tv-if=\"footLink\"\n\t\t\t\tclass=\"cn-object-parties__main-link\"\n\t\t\t\t:href=\"footLink.href\"\n\t\t\t\tdata-testid=\"cn-object-parties-main-link\">{{ footLink.label }}</a>\n\t\t</div>\n\n\t\t<NcEmptyContent\n\t\t\tv-else-if=\"groups.length === 0\"\n\t\t\t:name=\"label('empty')\"\n\t\t\t:description=\"label('emptyDetail')\"\n\t\t\tdata-testid=\"cn-object-parties-empty\" />\n\n\t\t<template v-else>\n\t\t\t<div\n\t\t\t\tv-if=\"kinds\"\n\t\t\t\tclass=\"cn-object-parties__accepted\"\n\t\t\t\t:data-source=\"kinds.source\"\n\t\t\t\tdata-testid=\"cn-object-parties-accepted\">\n\t\t\t\t<span class=\"cn-object-parties__accepted-label\">{{ label('accepted') }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-for=\"(kind, index) in kinds.kinds\"\n\t\t\t\t\t:key=\"kindCode(kind)\"\n\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default cn-object-parties__accepted-kind\"\n\t\t\t\t\tdata-testid=\"cn-object-parties-accepted-kind\">{{ index + 1 }}. {{ kind.label || kindCode(kind) }}</span>\n\t\t\t\t<span v-if=\"kindsSourceText\" class=\"cn-object-parties__muted\">{{ kindsSourceText }}</span>\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tv-if=\"verdicts.length > 0\"\n\t\t\t\tclass=\"cn-object-parties__verdicts\"\n\t\t\t\tdata-testid=\"cn-object-parties-verdicts\">\n\t\t\t\t<NcNoteCard\n\t\t\t\t\tv-for=\"verdict in verdicts\"\n\t\t\t\t\t:key=\"`${verdict.party}-${verdict.key}`\"\n\t\t\t\t\t:type=\"verdict.severity\"\n\t\t\t\t\t:data-effect=\"verdict.effect\"\n\t\t\t\t\tdata-testid=\"cn-object-parties-verdict\">\n\t\t\t\t\t<strong>{{ verdict.label }}</strong>\n\t\t\t\t\t<span>{{ verdict.sentence }}</span>\n\t\t\t\t</NcNoteCard>\n\t\t\t</div>\n\n\t\t\t<section\n\t\t\t\tv-for=\"group in groups\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-object-parties__role\"\n\t\t\t\t:data-role=\"group.key\"\n\t\t\t\t:aria-labelledby=\"`${idPrefix}-${group.key}`\"\n\t\t\t\tdata-testid=\"cn-object-parties-role\">\n\t\t\t\t<component :is=\"innerHeadingTag\" :id=\"`${idPrefix}-${group.key}`\" class=\"cn-object-parties__role-label cn-inner-heading\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</component>\n\t\t\t\t<ul class=\"cn-object-parties__list\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"party in group.parties\"\n\t\t\t\t\t\t:key=\"`${group.key}-${party.partyUuid || party.contactUid}`\"\n\t\t\t\t\t\tclass=\"cn-object-parties__party\"\n\t\t\t\t\t\t:data-party=\"party.partyUuid || party.contactUid\"\n\t\t\t\t\t\tdata-testid=\"cn-object-parties-party\">\n\t\t\t\t\t\t<span class=\"cn-object-parties__name\">{{ nameOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"primary && party.partyUuid === primary\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--primary\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-primary\">{{ label('primary') }}</span>\n\t\t\t\t\t\t<span v-if=\"kindOf(party)\" class=\"cn-object-parties__muted\">{{ kindOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"notAccepted(party)\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--warning\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-not-accepted\">{{ label('notAccepted') }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-for=\"(line, index) in extraLinesOf(party)\"\n\t\t\t\t\t\t\t:key=\"`line-${index}`\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-extra-line\">{{ line }}</span>\n\t\t\t\t\t\t<span v-if=\"party.email\" class=\"cn-object-parties__muted\">{{ party.email }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"representedBy(party)\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-represented\">{{ label('representedBy') }}: {{ representedBy(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"correspondenceOf(party)\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\t:data-party-documents=\"party.partyUuid || party.contactUid\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-documents\">{{ correspondenceOf(party) }}</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-for=\"indicator in indicatorsFor(party)\"\n\t\t\t\t\t\t\t:key=\"`${party.partyUuid}-${indicator.key}`\"\n\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default\"\n\t\t\t\t\t\t\t:class=\"`cn-object-parties__indicator--${indicator.severity}`\"\n\t\t\t\t\t\t\t:data-effect=\"indicator.effect\"\n\t\t\t\t\t\t\t:title=\"indicator.verdict\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-indicator\">{{ indicator.label }} · {{ indicator.verdict }}</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove && party.partyUuid\"\n\t\t\t\t\t\t\tclass=\"cn-object-parties__remove\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeLabel(party, group)\"\n\t\t\t\t\t\t\t:title=\"removeLabel(party, group)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-remove\"\n\t\t\t\t\t\t\t@click=\"removing = { party, group }\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<TrashCanOutline :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</template>\n\n\t\t<CnPartyAddDialog\n\t\t\tv-if=\"adding\"\n\t\t\tref=\"addDialog\"\n\t\t\t:dialogTitle=\"manageWord('add', 'dialogTitle', t('nextcloud-vue', 'Add a party'))\"\n\t\t\t:roles=\"addRoles\"\n\t\t\t:sources=\"addSources\"\n\t\t\t:createFields=\"createFields\"\n\t\t\t:createLabel=\"manageWord('add', 'createLabel', t('nextcloud-vue', 'Someone new'))\"\n\t\t\t:allowPrimary=\"content.manage.add.primary === true\"\n\t\t\t:primaryLabel=\"label('primary')\"\n\t\t\t:confirmLabel=\"manageWord('add', 'confirmLabel', t('nextcloud-vue', 'Add'))\"\n\t\t\t@close=\"adding = false\"\n\t\t\t@confirm=\"addParty\" />\n\n\t\t<CnConfirmDialog\n\t\t\tv-if=\"removing\"\n\t\t\tref=\"removeDialog\"\n\t\t\t:dialogTitle=\"manageWord('remove', 'title', t('nextcloud-vue', 'Remove party'))\"\n\t\t\t:message=\"removeMessage\"\n\t\t\t:confirmLabel=\"manageWord('remove', 'confirmLabel', t('nextcloud-vue', 'Remove'))\"\n\t\t\tvariant=\"error\"\n\t\t\t@close=\"removing = null\"\n\t\t\t@confirm=\"removeParty\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport EmailOutline from 'vue-material-design-icons/EmailOutline.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport TrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'\nimport CnConfirmDialog from '../../dialogs/CnConfirmDialog.vue'\nimport CnPartyAddDialog from '../../dialogs/CnPartyAddDialog.vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport innerHeading from '../../mixins/innerHeading.js'\nimport { conditionalLine } from '../../utils/conditionalLine.js'\nimport { initialsOf } from '../../utils/initials.js'\nimport {\n\tdocumentsOfParty,\n\tindicatorsOf,\n\tindicatorVerdict,\n\tkindCode,\n\tnewPartyRecord,\n\trepresentedByMap,\n\troleLabel,\n\trolesInOrder,\n\tsavedUuid,\n} from '../../utils/objectParties.js'\nimport { fetchCallerScope } from '../../utils/objectPermissions.js'\nimport { readPath } from '../../utils/readPath.js'\n\nlet uid = 0\n\n/**\n * The default words, keyed as `content.labels` overrides them.\n *\n * @return {object} The labels.\n */\nfunction defaultLabels() {\n\treturn {\n\t\tfailed: t('nextcloud-vue', 'The parties could not be read'),\n\t\tfailedDetail: t('nextcloud-vue', 'OpenRegister did not answer. Nothing has been removed.'),\n\t\tempty: t('nextcloud-vue', 'No parties yet'),\n\t\temptyDetail: t('nextcloud-vue', 'Add a party to record who this is for and who acts on it.'),\n\t\taccepted: t('nextcloud-vue', 'Accepted kinds'),\n\t\tprimary: t('nextcloud-vue', 'Primary party'),\n\t\tnotAccepted: t('nextcloud-vue', 'Kind not accepted here'),\n\t\trepresentedBy: t('nextcloud-vue', 'Represented by'),\n\t\tnoPrimary: t('nextcloud-vue', 'No main contact yet'),\n\t}\n}\n\n/**\n * CnObjectPartiesWidget — the `parties` widget: a record's parties as\n * OpenRegister's party model answers them, grouped by role with the primary\n * party first. Each party shows its kind, its representative and the\n * indicators on it, each with its verdict. A blocking verdict is also a note\n * above the list, so nobody publishes or sends past it.\n *\n * ```json\n * {\n * \"type\": \"parties\",\n * \"content\": {\n * \"rolesObjects\": { \"register\": \"myapp\", \"schema\": \"role\", \"field\": \"item\" },\n * \"roleLabels\": { \"applicant\": \"Applicant\" },\n * \"kindsSource\": { \"url\": \"/apps/myapp/api/items/@objectId/party-kinds\", \"enforce\": \"crm\" },\n * \"extraLines\": [{ \"endpoint\": \"/apps/myapp/api/items/@objectId/parties/{party}/language\", \"lines\": [\"Language: {language}\"] }],\n * \"correspondence\": { \"endpoint\": \"/apps/myapp/api/items/@objectId/documents\", \"path\": \"documents\" }\n * }\n * }\n * ```\n *\n * `manage` lets a reader change the parties through OpenRegister's party\n * API, which asks the record's update right on every write: `add` (`{ label?,\n * dialogTitle?, kind?, sources, create?, primary?, confirmLabel? }`) opens a\n * dialog to pick somebody known or describe somebody new (`create: {\n * register, schema, label?, fields, compose? }`, see `newPartyRecord`), choose\n * a role and optionally make them the primary party; `remove` (`{ title?,\n * message?, confirmLabel? }`, `{name}` and `{role}` in the message) takes a\n * party off in one role. Both are hidden when OpenRegister says the reader\n * may not update the schema; a refusal is shown, never swallowed.\n *\n * `presentation: \"primary\"` draws only the primary party, as a side card\n * does: initials, name and role label, its correspondence e-mail, and\n * `link` (`{ label, href? | tab? }`, `{total}` = the number of parties) at\n * the foot; `tab` opens that tab of the page through the route hash. It\n * reads the listing only.\n *\n * A failed read says so and is never shown as \"no parties\".\n *\n * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-shows-its-parties-by-role\n */\nexport default {\n\tname: 'CnObjectPartiesWidget',\n\n\tcomponents: { CnConfirmDialog, CnPartyAddDialog, EmailOutline, NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard, Plus, TrashCanOutline },\n\n\tmixins: [innerHeading],\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The configuration: `rolesSource` (the listing URL, default\n\t\t * OpenRegister's `/parties` of this record), `partySource` (one\n\t\t * party, `{uuid}` filled in), `rolesObjects` (`{ register, schema,\n\t\t * field }`, the role rows that say who represents whom), `roleLabels`,\n\t\t * `kindsSource` (`{ url, enforce?, sourceText? }`), `extraLines`\n\t\t * (`[{ endpoint, path?, valueLabels?, lines }]`, one request per\n\t\t * party, `{party}` filled in), `correspondence` (`{ endpoint, path?,\n\t\t * senderField?, recipientsField? }`), `labels`, `presentation`\n\t\t * (`\"primary\"`: only the primary party) and `link` (`{ label,\n\t\t * href? | tab? }`, the primary presentation's foot link) and\n\t\t * `manage` (`{ add?, remove? }`, adding and removing parties).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, bound by the detail host. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's register slug. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's schema slug. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\tuid += 1\n\t\treturn {\n\t\t\tidPrefix: `cn-object-parties-${uid}`,\n\t\t\tloading: true,\n\t\t\tfailed: false,\n\t\t\tlisting: null,\n\t\t\tpartyRecords: {},\n\t\t\trepresented: {},\n\t\t\tkinds: null,\n\t\t\textra: {},\n\t\t\tdocuments: [],\n\t\t\tmayUpdate: true,\n\t\t\tadding: false,\n\t\t\tremoving: null,\n\t\t\tmanageError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {Array<object>} The role groups, primary first. */\n\t\tgroups() {\n\t\t\treturn rolesInOrder(this.listing, this.translatedMap(this.content?.roleLabels))\n\t\t},\n\n\t\t/** @return {object} The `manage` declaration, or an empty one. */\n\t\tmanage() {\n\t\t\tconst manage = this.content?.manage\n\t\t\treturn manage && typeof manage === 'object' ? manage : {}\n\t\t},\n\n\t\t/** @return {boolean} Whether the add button shows. */\n\t\tcanAdd() {\n\t\t\treturn Boolean(this.manage.add) && this.mayUpdate && !this.isPrimaryPresentation && !this.loading && !this.failed\n\t\t},\n\n\t\t/** @return {boolean} Whether each party offers its remove button. */\n\t\tcanRemove() {\n\t\t\treturn Boolean(this.manage.remove) && this.mayUpdate && !this.isPrimaryPresentation\n\t\t},\n\n\t\t/** @return {Array<{key: string, label: string}>} The roles a new party may hold, in the reader's words. */\n\t\taddRoles() {\n\t\t\tconst declared = Array.isArray(this.listing?.roles) ? this.listing.roles : []\n\t\t\tconst kind = this.manage.add?.kind\n\t\t\tconst accepted = kind ? (this.listing?.kinds || []).find((entry) => kindCode(entry) === kind)?.roles : null\n\t\t\tconst keys = Array.isArray(accepted) && accepted.length > 0 ? accepted : declared.map((role) => role?.key).filter(Boolean)\n\t\t\tconst own = this.translatedMap(this.content?.roleLabels)\n\t\t\treturn keys.map((key) => ({ key, label: own[key] || this.cnTranslate(roleLabel(key, declared, {})) }))\n\t\t},\n\n\t\t/** @return {Array<object>} The picker sources, their words translated by the picker. */\n\t\taddSources() {\n\t\t\treturn Array.isArray(this.manage.add?.sources) ? this.manage.add.sources : []\n\t\t},\n\n\t\t/** @return {Array<object>} The new-person fields, labels translated. */\n\t\tcreateFields() {\n\t\t\tconst fields = this.manage.add?.create?.fields\n\t\t\treturn (Array.isArray(fields) ? fields : [])\n\t\t\t\t.filter((field) => field && field.key)\n\t\t\t\t.map((field) => ({ ...field, label: this.cnTranslate(field.label || field.key) }))\n\t\t},\n\n\t\t/** @return {string} The question the remove dialog asks. */\n\t\tremoveMessage() {\n\t\t\tif (!this.removing) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst name = this.nameOf(this.removing.party)\n\t\t\tconst role = this.removing.group.label\n\t\t\tconst own = this.manage.remove?.message\n\t\t\treturn own\n\t\t\t\t? this.cnTranslate(own).replaceAll('{name}', name).replaceAll('{role}', role)\n\t\t\t\t: t('nextcloud-vue', 'Remove {name} as {role}?', { name, role }, undefined, { escape: false })\n\t\t},\n\n\t\t/** @return {boolean} Whether only the primary party is drawn. */\n\t\tisPrimaryPresentation() {\n\t\t\treturn this.content?.presentation === 'primary'\n\t\t},\n\n\t\t/** @return {object|null} The primary party's listing row. */\n\t\tmainParty() {\n\t\t\tif (!this.primary) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (this.listing?.results || []).find((row) => row && row.partyUuid === this.primary) || null\n\t\t},\n\n\t\t/** @return {string} The primary party's role, in the app's words. */\n\t\tmainRole() {\n\t\t\tconst key = this.mainParty?.role\n\t\t\tif (!key) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst own = this.translatedMap(this.content?.roleLabels)\n\t\t\tif (typeof own[key] === 'string' && own[key] !== '') {\n\t\t\t\treturn own[key]\n\t\t\t}\n\t\t\treturn this.cnTranslate(roleLabel(key, this.listing?.roles, {}))\n\t\t},\n\n\t\t/** @return {{label: string, href: string}|null} The primary presentation's foot link; none without parties. */\n\t\tfootLink() {\n\t\t\tconst link = this.content?.link\n\t\t\tconst total = Number(this.listing?.total ?? (this.listing?.results || []).length)\n\t\t\tif (!link || typeof link !== 'object' || !link.label || !(total > 0)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst href = link.tab ? `#${encodeURIComponent(link.tab)}` : (link.href || '')\n\t\t\tif (href === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { label: this.cnTranslate(link.label).replaceAll('{total}', String(total)), href }\n\t\t},\n\n\t\t/** @return {string|null} The primary party's uuid. */\n\t\tprimary() {\n\t\t\treturn this.listing?.primary || null\n\t\t},\n\n\t\t/** @return {object} The verdict words, translated. */\n\t\tverdictLabels() {\n\t\t\tconst own = this.content?.labels || {}\n\t\t\tconst out = {}\n\t\t\tfor (const key of ['verdictPublication', 'verdictSend', 'verdictWarn']) {\n\t\t\t\tif (typeof own[key] === 'string' && own[key] !== '') {\n\t\t\t\t\tout[key] = this.cnTranslate(own[key])\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/** @return {Array<object>} The blocking verdicts, as notes above the list. */\n\t\tverdicts() {\n\t\t\treturn indicatorsOf(Object.values(this.partyRecords))\n\t\t\t\t.map((indicator) => ({\n\t\t\t\t\t...indicatorVerdict(indicator, this.verdictLabels),\n\t\t\t\t\tparty: indicator.party,\n\t\t\t\t\tkey: indicator.key,\n\t\t\t\t\tsentence: this.sentenceFor(indicator),\n\t\t\t\t}))\n\t\t\t\t.filter((verdict) => verdict.severity === 'error')\n\t\t},\n\n\t\t/** @return {string} Where the accepted kinds come from. */\n\t\tkindsSourceText() {\n\t\t\tconst texts = this.content?.kindsSource?.sourceText\n\t\t\tif (!this.kinds || !texts || typeof texts !== 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst text = texts[this.kinds.source] || texts.default || ''\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** @return {Record<string, string>} The kind labels the listing declares. */\n\t\tkindLabels() {\n\t\t\tconst labels = {}\n\t\t\tfor (const kind of this.listing?.kinds || []) {\n\t\t\t\tif (kind && kind.key) {\n\t\t\t\t\tlabels[kind.key] = kind.label || kind.key\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn labels\n\t\t},\n\n\t\t/** @return {string} A key that changes when the record does. */\n\t\trecordKey() {\n\t\t\treturn `${this.register}|${this.schema}|${this.objectId}`\n\t\t},\n\t},\n\n\twatch: {\n\t\trecordKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.onPageRefresh = (payload) => {\n\t\t\tif (payload?.source !== this.idPrefix) {\n\t\t\t\tthis.load()\n\t\t\t}\n\t\t}\n\t\tsubscribe('cn:page:refresh', this.onPageRefresh)\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.onPageRefresh)\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tinitialsOf,\n\t\tkindCode,\n\n\t\t/**\n\t\t * A label: the content's own (translated), else the default.\n\t\t *\n\t\t * @param {string} key The label key.\n\t\t * @return {string}\n\t\t */\n\t\tlabel(key) {\n\t\t\tconst own = this.content?.labels && typeof this.content.labels[key] === 'string' ? this.content.labels[key] : ''\n\t\t\treturn own !== '' ? this.cnTranslate(own) : defaultLabels()[key]\n\t\t},\n\n\t\t/**\n\t\t * A word of the `manage` declaration, translated, else the default.\n\t\t *\n\t\t * @param {string} part `add` or `remove`.\n\t\t * @param {string} key The word's key.\n\t\t * @param {string} fallback The default.\n\t\t * @return {string}\n\t\t */\n\t\tmanageWord(part, key, fallback) {\n\t\t\tconst own = this.manage[part]?.[key]\n\t\t\treturn typeof own === 'string' && own !== '' ? this.cnTranslate(own) : fallback\n\t\t},\n\n\t\t/**\n\t\t * The remove button's accessible name.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @param {object} group The role group.\n\t\t * @return {string}\n\t\t */\n\t\tremoveLabel(party, group) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as {role}', { name: this.nameOf(party), role: group.label }, undefined, { escape: false })\n\t\t},\n\n\t\t/**\n\t\t * Why a write failed, in the reader's words.\n\t\t *\n\t\t * @param {unknown} error The axios error.\n\t\t * @return {string}\n\t\t */\n\t\trefusalOf(error) {\n\t\t\tif (error?.response?.status === 403) {\n\t\t\t\treturn t('nextcloud-vue', 'You may not change who is on this record.')\n\t\t\t}\n\t\t\tconst said = error?.response?.data?.error\n\t\t\treturn typeof said === 'string' && said !== '' ? said : t('nextcloud-vue', 'The change could not be saved. Nothing was changed.')\n\t\t},\n\n\t\t/** @return {string} The record's parties URL. */\n\t\tpartiesUrl() {\n\t\t\treturn this.urlOf(this.content?.rolesSource || '/apps/openregister/api/objects/@register/@schema/@objectId/parties')\n\t\t},\n\n\t\t/** @return {Promise<void>} Whether OpenRegister lets the reader update this schema; unknown counts as yes, the server decides. */\n\t\tasync loadMayUpdate() {\n\t\t\tif (!this.manage.add && !this.manage.remove) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst slug = (value) => (value && typeof value === 'object' ? String(value.slug || value.id || '') : String(value || ''))\n\t\t\tconst scope = await fetchCallerScope({ register: slug(this.register), schema: slug(this.schema) })\n\t\t\tthis.mayUpdate = !scope || !Array.isArray(scope.actions) || scope.actions.includes('update')\n\t\t},\n\n\t\t/**\n\t\t * Create the person when they are new, then give them the role; a\n\t\t * primary party is set through the primary route, which records the\n\t\t * replacement.\n\t\t *\n\t\t * @param {{mode: string, partyUuid: string|null, values: object, role: string, primary: boolean}} choice The dialog's choice.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync addParty(choice) {\n\t\t\ttry {\n\t\t\t\tlet partyUuid = choice.partyUuid\n\t\t\t\tif (choice.mode === 'new') {\n\t\t\t\t\tconst create = this.manage.add?.create || {}\n\t\t\t\t\tconst { data } = await axios.post(\n\t\t\t\t\t\tgenerateUrl(`/apps/openregister/api/objects/${encodeURIComponent(create.register || '')}/${encodeURIComponent(create.schema || '')}`),\n\t\t\t\t\t\tnewPartyRecord(create, choice.values),\n\t\t\t\t\t)\n\t\t\t\t\tpartyUuid = savedUuid(data)\n\t\t\t\t\tif (partyUuid === '') {\n\t\t\t\t\t\tthrow new Error(t('nextcloud-vue', 'The new person was not saved.'))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (choice.primary) {\n\t\t\t\t\tawait axios.put(generateUrl(`${this.partiesUrl()}/primary`), { partyUuid, role: choice.role })\n\t\t\t\t} else {\n\t\t\t\t\tawait axios.post(generateUrl(this.partiesUrl()), { partyUuid, role: choice.role })\n\t\t\t\t}\n\t\t\t\tthis.adding = false\n\t\t\t\tthis.changed()\n\t\t\t} catch (error) {\n\t\t\t\tthis.$refs.addDialog?.fail(error?.response ? this.refusalOf(error) : (error?.message || this.refusalOf(error)))\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} Take the chosen party off in the chosen role. */\n\t\tasync removeParty() {\n\t\t\tconst { party, group } = this.removing || {}\n\t\t\tif (!party) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait axios.delete(generateUrl(`${this.partiesUrl()}/${encodeURIComponent(party.partyUuid)}`), { params: { role: group.key } })\n\t\t\t\tthis.removing = null\n\t\t\t\tthis.changed()\n\t\t\t} catch (error) {\n\t\t\t\tthis.$refs.removeDialog?.setResult({ error: this.refusalOf(error) })\n\t\t\t}\n\t\t},\n\n\t\t/** @return {void} Read the parties again and tell the page (tab counts, the side card). */\n\t\tchanged() {\n\t\t\tthis.manageError = ''\n\t\t\tthis.load()\n\t\t\temit('cn:page:refresh', { source: this.idPrefix })\n\t\t},\n\n\t\t/**\n\t\t * A map of manifest words, translated.\n\t\t *\n\t\t * @param {object} map The map.\n\t\t * @return {Record<string, string>}\n\t\t */\n\t\ttranslatedMap(map) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(map && typeof map === 'object' ? map : {})) {\n\t\t\t\tout[key] = typeof value === 'string' ? this.cnTranslate(value) : value\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * An app path with the record's tokens and `{party}` filled in.\n\t\t *\n\t\t * @param {string} template The path.\n\t\t * @param {string} [party] A party uuid.\n\t\t * @return {string}\n\t\t */\n\t\turlOf(template, party = '') {\n\t\t\tconst withSlugs = String(template)\n\t\t\t\t.replaceAll('@register', String(this.register || ''))\n\t\t\t\t.replaceAll('@schema', String(this.schema || ''))\n\t\t\treturn interpolateUrlTokens(withSlugs, { objectId: this.objectId }).replaceAll('{party}', encodeURIComponent(party)).replaceAll('{uuid}', encodeURIComponent(party))\n\t\t},\n\n\t\t/**\n\t\t * GET an app path; null when it fails.\n\t\t *\n\t\t * @param {string} path The app path.\n\t\t * @param {object} [params] Query parameters.\n\t\t * @return {Promise<unknown>}\n\t\t */\n\t\tasync read(path, params) {\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.get(generateUrl(path), params ? { params } : undefined)\n\t\t\t\treturn data ?? null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the listing, then each party, the representation, the kinds,\n\t\t * the extra lines and the correspondence.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.objectId) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\tthis.partyRecords = {}\n\t\t\tthis.represented = {}\n\t\t\tthis.extra = {}\n\t\t\tthis.documents = []\n\t\t\tconst listing = await this.read(this.urlOf(this.content?.rolesSource || '/apps/openregister/api/objects/@register/@schema/@objectId/parties'))\n\t\t\tif (!listing || typeof listing !== 'object') {\n\t\t\t\tthis.failed = true\n\t\t\t\tthis.listing = null\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.listing = listing\n\t\t\tawait this.loadMayUpdate()\n\t\t\tif (this.isPrimaryPresentation) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst uuids = [...new Set((listing.results || []).map((row) => row && row.partyUuid).filter(Boolean))]\n\t\t\tconst partyUrl = this.content?.partySource || '/apps/openregister/api/parties/{uuid}'\n\t\t\tconst records = await Promise.all(uuids.map((uuid) => this.read(this.urlOf(partyUrl, uuid))))\n\t\t\tconst byUuid = {}\n\t\t\tuuids.forEach((uuid, index) => {\n\t\t\t\tif (records[index] && typeof records[index] === 'object') {\n\t\t\t\t\tbyUuid[uuid] = records[index]\n\t\t\t\t}\n\t\t\t})\n\t\t\tthis.partyRecords = byUuid\n\t\t\tawait Promise.all([this.loadRepresentation(), this.loadKinds(), this.loadExtraLines(uuids), this.loadCorrespondence()])\n\t\t\tthis.loading = false\n\t\t},\n\n\t\t/** @return {Promise<void>} Who represents whom, from the role rows. */\n\t\tasync loadRepresentation() {\n\t\t\tconst source = this.content?.rolesObjects\n\t\t\tif (!source || !source.register || !source.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(`/apps/openregister/api/objects/${encodeURIComponent(source.register)}/${encodeURIComponent(source.schema)}`, { [source.field || 'object']: String(this.objectId), _limit: 200 })\n\t\t\tconst rows = Array.isArray(data?.results) ? data.results : (Array.isArray(data) ? data : [])\n\t\t\tthis.represented = representedByMap(rows)\n\t\t},\n\n\t\t/** @return {Promise<void>} The kinds this record accepts. */\n\t\tasync loadKinds() {\n\t\t\tconst source = this.content?.kindsSource\n\t\t\tthis.kinds = null\n\t\t\tif (!source || !source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(this.urlOf(source.url))\n\t\t\tthis.kinds = data && Array.isArray(data.kinds) ? data : null\n\t\t},\n\n\t\t/**\n\t\t * One answer per party per extra line.\n\t\t *\n\t\t * @param {Array<string>} uuids The parties.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadExtraLines(uuids) {\n\t\t\tconst lines = Array.isArray(this.content?.extraLines) ? this.content.extraLines : []\n\t\t\tconst extra = {}\n\t\t\tawait Promise.all(lines.map(async (spec, index) => {\n\t\t\t\tif (!spec || !spec.endpoint) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst answers = await Promise.all(uuids.map((uuid) => this.read(this.urlOf(spec.endpoint, uuid))))\n\t\t\t\tuuids.forEach((uuid, i) => {\n\t\t\t\t\tconst answer = spec.path ? readPath(answers[i], spec.path) : answers[i]\n\t\t\t\t\tif (answer && typeof answer === 'object') {\n\t\t\t\t\t\textra[`${index}|${uuid}`] = answer\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}))\n\t\t\tthis.extra = extra\n\t\t},\n\n\t\t/** @return {Promise<void>} The documents the correspondence counts read. */\n\t\tasync loadCorrespondence() {\n\t\t\tconst spec = this.content?.correspondence\n\t\t\tif (!spec || !spec.endpoint) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(this.urlOf(spec.endpoint))\n\t\t\tconst list = spec.path ? readPath(data, spec.path) : data\n\t\t\tthis.documents = Array.isArray(list) ? list : []\n\t\t},\n\n\t\t/**\n\t\t * The extra lines for a party, each the first of its `lines` that applies.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {Array<string>}\n\t\t */\n\t\textraLinesOf(party) {\n\t\t\tconst specs = Array.isArray(this.content?.extraLines) ? this.content.extraLines : []\n\t\t\treturn specs.map((spec, index) => {\n\t\t\t\tconst answer = this.extra[`${index}|${party.partyUuid}`]\n\t\t\t\tif (!answer) {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn conditionalLine(spec.lines || [], this.labelled(answer, spec.valueLabels), (text) => this.cnTranslate(text))\n\t\t\t}).filter((line) => line !== '')\n\t\t},\n\n\t\t/**\n\t\t * An answer with its coded values replaced by their labels\n\t\t * (`valueLabels: { language: { nl: \"Dutch\" } }`; `nl-NL` reads as `nl`).\n\t\t *\n\t\t * @param {object} answer The answer.\n\t\t * @param {object} valueLabels The labels by field and value.\n\t\t * @return {object}\n\t\t */\n\t\tlabelled(answer, valueLabels) {\n\t\t\tif (!valueLabels || typeof valueLabels !== 'object') {\n\t\t\t\treturn answer\n\t\t\t}\n\t\t\tconst out = { ...answer }\n\t\t\tfor (const [field, map] of Object.entries(valueLabels)) {\n\t\t\t\tconst raw = answer[field]\n\t\t\t\tif (typeof raw !== 'string' || !map) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst hit = map[raw] ?? map[raw.toLowerCase().split('-')[0]]\n\t\t\t\tif (typeof hit === 'string') {\n\t\t\t\t\tout[field] = this.cnTranslate(hit)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether a party's kind is one this record does not accept. Only when\n\t\t * the kinds come from the source named by `kindsSource.enforce`.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {boolean}\n\t\t */\n\t\tnotAccepted(party) {\n\t\t\tconst enforce = this.content?.kindsSource?.enforce\n\t\t\tif (!party?.partyKind || !this.kinds || (enforce && this.kinds.source !== enforce)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !this.kinds.kinds.some((kind) => kindCode(kind) === party.partyKind)\n\t\t},\n\n\t\t/**\n\t\t * A party's kind: the accepted kind's label, else the listing's, else the code.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tkindOf(party) {\n\t\t\tif (!party.partyKind) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst offered = (this.kinds?.kinds || []).find((kind) => kindCode(kind) === party.partyKind)\n\t\t\treturn offered?.label || this.kindLabels[party.partyKind] || party.partyKind\n\t\t},\n\n\t\t/**\n\t\t * Who represents this party, by name.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\trepresentedBy(party) {\n\t\t\tconst uuid = this.represented[party.partyUuid || party.contactUid || ''] || ''\n\t\t\tif (uuid === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst row = (this.listing?.results || []).find((candidate) => candidate?.partyUuid === uuid)\n\t\t\treturn row ? this.nameOf(row) : (this.partyRecords[uuid]?.name || uuid)\n\t\t},\n\n\t\t/**\n\t\t * A party's name: the listing's, else the party record's, else its id.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tnameOf(party) {\n\t\t\treturn party.displayName || this.partyRecords[party.partyUuid]?.name || party.contactUid || party.partyUuid || ''\n\t\t},\n\n\t\t/**\n\t\t * How many documents a party sent and received.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tcorrespondenceOf(party) {\n\t\t\tconst spec = this.content?.correspondence || {}\n\t\t\tconst { sent, received } = documentsOfParty(this.documents, party.partyUuid || party.contactUid || '', spec)\n\t\t\tif (sent.length === 0 && received.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (received.length === 0) {\n\t\t\t\treturn n('nextcloud-vue', '%n document sent', '%n documents sent', sent.length)\n\t\t\t}\n\t\t\tif (sent.length === 0) {\n\t\t\t\treturn n('nextcloud-vue', '%n document received', '%n documents received', received.length)\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{sent} sent, {received} received', { sent: sent.length, received: received.length })\n\t\t},\n\n\t\t/**\n\t\t * The indicators on a party, each with its verdict.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {Array<object>}\n\t\t */\n\t\tindicatorsFor(party) {\n\t\t\tconst record = this.partyRecords[party.partyUuid]\n\t\t\tif (!record) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn (record.indicators || []).filter(Boolean).map((indicator) => ({ ...indicatorVerdict(indicator, this.verdictLabels), key: indicator.key }))\n\t\t},\n\n\t\t/**\n\t\t * The sentence of a blocking verdict, naming the party.\n\t\t *\n\t\t * @param {object} indicator The indicator with `partyName`.\n\t\t * @return {string}\n\t\t */\n\t\tsentenceFor(indicator) {\n\t\t\tconst name = indicator.partyName || indicator.party\n\t\t\tconst own = this.content?.labels || {}\n\t\t\tif (indicatorVerdict(indicator).effect === 'refuse-publication') {\n\t\t\t\treturn own.sentencePublication\n\t\t\t\t\t? this.cnTranslate(own.sentencePublication).replaceAll('{party}', name)\n\t\t\t\t\t: t('nextcloud-vue', 'Publishing a file on this record is refused, because of {party}.', { party: name }, undefined, { escape: false })\n\t\t\t}\n\t\t\treturn own.sentenceSend\n\t\t\t\t? this.cnTranslate(own.sentenceSend).replaceAll('{party}', name)\n\t\t\t\t: t('nextcloud-vue', 'A message to {party} is refused.', { party: name }, undefined, { escape: false })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-parties {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__verdicts {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline, 4px);\n}\n\n.cn-object-parties__role-label {\n\tmargin: 0 0 var(--default-grid-baseline, 4px) 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-object-parties__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline, 4px);\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-object-parties__party {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2);\n\tpadding: var(--default-grid-baseline, 4px);\n\tborder-radius: var(--border-radius, 4px);\n}\n\n.cn-object-parties__party:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-parties__name {\n\tfont-weight: bold;\n}\n\n.cn-object-parties__muted {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-parties__manage {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n}\n\n.cn-object-parties__remove {\n\tmargin-inline-start: auto;\n}\n\n.cn-object-parties__main-card {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__main {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__main-initials {\n\tdisplay: flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n}\n\n.cn-object-parties__main-text {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-object-parties__main-name {\n\tfont-size: 15px;\n}\n\n.cn-object-parties__main-role {\n\tfont-size: 13px;\n}\n\n.cn-object-parties__main-email {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2.5);\n\tcolor: var(--color-main-text);\n\toverflow-wrap: anywhere;\n}\n\n.cn-object-parties__main-link {\n\tcolor: var(--color-primary-element);\n\tfont-weight: 600;\n}\n\n.cn-object-parties__accepted {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2);\n\tpadding: calc(var(--default-grid-baseline, 4px) * 2) calc(var(--default-grid-baseline, 4px) * 3);\n\tborder-radius: var(--border-radius-large, 10px);\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-parties__accepted-label {\n\tfont-weight: 600;\n}\n\n.cn-object-parties__accepted-kind {\n\tborder: 1px solid var(--color-border-dark);\n}\n</style>\n"],"names":["_createVNode","_toDisplayString","_createBlock","_openBlock","_createElementBlock","_createElementVNode","_createTextVNode","_Fragment","_renderList","_resolveDynamicComponent","_normalizeClass"],"mappings":"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"}
1
+ {"version":3,"file":"CnObjectPartiesWidget.vue3.js","sources":["../../../../src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue?vue&type=template&id=44731ec4&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-object-parties\" :class=\"{ 'cn-object-parties--board': isBoard }\" data-testid=\"cn-object-parties\">\n\t\t<div v-if=\"canAdd\" class=\"cn-object-parties__manage\">\n\t\t\t<NcButton data-testid=\"cn-object-parties-add\" @click=\"adding = true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ manageWord('add', 'label', t('nextcloud-vue', 'Add a party')) }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<NcNoteCard\n\t\t\tv-if=\"manageError\"\n\t\t\ttype=\"error\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-object-parties-manage-error\">\n\t\t\t{{ manageError }}\n\t\t</NcNoteCard>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"24\" />\n\n\t\t<NcEmptyContent\n\t\t\tv-else-if=\"failed\"\n\t\t\t:name=\"label('failed')\"\n\t\t\t:description=\"label('failedDetail')\"\n\t\t\tdata-testid=\"cn-object-parties-failed\" />\n\n\t\t<div\n\t\t\tv-else-if=\"isPrimaryPresentation\"\n\t\t\tclass=\"cn-object-parties__main-card\"\n\t\t\tdata-testid=\"cn-object-parties-main-card\">\n\t\t\t<div\n\t\t\t\tv-if=\"mainParty\"\n\t\t\t\tclass=\"cn-object-parties__main\"\n\t\t\t\t:data-party=\"mainParty.partyUuid\"\n\t\t\t\tdata-testid=\"cn-object-parties-main\">\n\t\t\t\t<span class=\"cn-object-parties__main-initials\" aria-hidden=\"true\" data-testid=\"cn-object-parties-main-initials\">{{ initialsOf(nameOf(mainParty)) }}</span>\n\t\t\t\t<span class=\"cn-object-parties__main-text\">\n\t\t\t\t\t<strong class=\"cn-object-parties__main-name\" data-testid=\"cn-object-parties-main-name\">{{ nameOf(mainParty) }}</strong>\n\t\t\t\t\t<span v-if=\"mainRole\" class=\"cn-object-parties__muted cn-object-parties__main-role\" data-testid=\"cn-object-parties-main-role\">{{ mainRole }}</span>\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<span v-else class=\"cn-object-parties__muted\" data-testid=\"cn-object-parties-main-none\">{{ label('noPrimary') }}</span>\n\t\t\t<a\n\t\t\t\tv-if=\"mainParty && mainParty.email\"\n\t\t\t\tclass=\"cn-object-parties__main-email\"\n\t\t\t\t:href=\"`mailto:${mainParty.email}`\"\n\t\t\t\tdata-testid=\"cn-object-parties-main-email\">\n\t\t\t\t<EmailOutline :size=\"16\" aria-hidden=\"true\" />{{ mainParty.email }}</a>\n\t\t\t<a\n\t\t\t\tv-if=\"footLink\"\n\t\t\t\tclass=\"cn-object-parties__main-link\"\n\t\t\t\t:href=\"footLink.href\"\n\t\t\t\tdata-testid=\"cn-object-parties-main-link\">{{ footLink.label }}</a>\n\t\t</div>\n\n\t\t<NcEmptyContent\n\t\t\tv-else-if=\"groups.length === 0\"\n\t\t\t:name=\"label('empty')\"\n\t\t\t:description=\"label('emptyDetail')\"\n\t\t\tdata-testid=\"cn-object-parties-empty\" />\n\n\t\t<template v-else>\n\t\t\t<div\n\t\t\t\tv-if=\"kinds\"\n\t\t\t\tclass=\"cn-object-parties__accepted\"\n\t\t\t\t:data-source=\"kinds.source\"\n\t\t\t\tdata-testid=\"cn-object-parties-accepted\">\n\t\t\t\t<span class=\"cn-object-parties__accepted-label\">{{ label('accepted') }}</span>\n\t\t\t\t<span\n\t\t\t\t\tv-for=\"(kind, index) in kinds.kinds\"\n\t\t\t\t\t:key=\"kindCode(kind)\"\n\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default cn-object-parties__accepted-kind\"\n\t\t\t\t\tdata-testid=\"cn-object-parties-accepted-kind\">{{ index + 1 }}. {{ kind.label || kindCode(kind) }}</span>\n\t\t\t\t<span v-if=\"kindsSourceText\" class=\"cn-object-parties__muted\">{{ kindsSourceText }}</span>\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tv-if=\"verdicts.length > 0\"\n\t\t\t\tclass=\"cn-object-parties__verdicts\"\n\t\t\t\tdata-testid=\"cn-object-parties-verdicts\">\n\t\t\t\t<NcNoteCard\n\t\t\t\t\tv-for=\"verdict in verdicts\"\n\t\t\t\t\t:key=\"`${verdict.party}-${verdict.key}`\"\n\t\t\t\t\t:type=\"verdict.severity\"\n\t\t\t\t\t:data-effect=\"verdict.effect\"\n\t\t\t\t\tdata-testid=\"cn-object-parties-verdict\">\n\t\t\t\t\t<strong>{{ verdict.label }}</strong>\n\t\t\t\t\t<span>{{ verdict.sentence }}</span>\n\t\t\t\t</NcNoteCard>\n\t\t\t</div>\n\n\t\t\t<section\n\t\t\t\tv-for=\"group in groups\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-object-parties__role\"\n\t\t\t\t:data-role=\"group.key\"\n\t\t\t\t:aria-labelledby=\"`${idPrefix}-${group.key}`\"\n\t\t\t\tdata-testid=\"cn-object-parties-role\">\n\t\t\t\t<component :is=\"innerHeadingTag\" :id=\"`${idPrefix}-${group.key}`\" class=\"cn-object-parties__role-label cn-inner-heading\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</component>\n\t\t\t\t<ul class=\"cn-object-parties__list\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"party in group.parties\"\n\t\t\t\t\t\t:key=\"`${group.key}-${party.partyUuid || party.contactUid}`\"\n\t\t\t\t\t\tclass=\"cn-object-parties__party\"\n\t\t\t\t\t\t:data-party=\"party.partyUuid || party.contactUid\"\n\t\t\t\t\t\tdata-testid=\"cn-object-parties-party\">\n\t\t\t\t\t\t<!-- The board look draws a party as one ruled row (DqZaakBetrokkenen\n\t\t\t\t\t\t \"Rollen\"): an initials tile, the name over one meta line that\n\t\t\t\t\t\t names the role, the pills at the end. -->\n\t\t\t\t\t\t<template v-if=\"isBoard\">\n\t\t\t\t\t\t\t<span class=\"cn-object-parties__tile\" aria-hidden=\"true\">{{ initialsOf(nameOf(party)) }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-object-parties__text\">\n\t\t\t\t\t\t\t\t<span class=\"cn-object-parties__name\">{{ nameOf(party) }}</span>\n\t\t\t\t\t\t\t\t<span class=\"cn-object-parties__meta\" data-testid=\"cn-object-parties-meta\">{{ boardMetaOf(party, group) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span class=\"cn-object-parties__end\">\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tv-if=\"notAccepted(party)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--warning\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-not-accepted\">{{ label('notAccepted') }}</span>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tv-for=\"indicator in indicatorsFor(party)\"\n\t\t\t\t\t\t\t\t\t:key=\"`${party.partyUuid}-${indicator.key}`\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default\"\n\t\t\t\t\t\t\t\t\t:class=\"`cn-object-parties__indicator--${indicator.severity}`\"\n\t\t\t\t\t\t\t\t\t:data-effect=\"indicator.effect\"\n\t\t\t\t\t\t\t\t\t:title=\"indicator.verdict\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-indicator\">{{ indicator.label }}</span>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tv-if=\"canRemove && party.partyUuid\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-object-parties__remove\"\n\t\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"removeLabel(party, group)\"\n\t\t\t\t\t\t\t\t\t:title=\"removeLabel(party, group)\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-remove\"\n\t\t\t\t\t\t\t\t\t@click=\"removing = { party, group }\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<TrashCanOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t<span class=\"cn-object-parties__name\">{{ nameOf(party) }}</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"primary && party.partyUuid === primary\"\n\t\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--primary\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-primary\">{{ label('primary') }}</span>\n\t\t\t\t\t\t\t<span v-if=\"kindOf(party)\" class=\"cn-object-parties__muted\">{{ kindOf(party) }}</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"notAccepted(party)\"\n\t\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--warning\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-not-accepted\">{{ label('notAccepted') }}</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-for=\"(line, index) in extraLinesOf(party)\"\n\t\t\t\t\t\t\t\t:key=\"`line-${index}`\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-extra-line\">{{ line }}</span>\n\t\t\t\t\t\t\t<span v-if=\"party.email\" class=\"cn-object-parties__muted\">{{ party.email }}</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"representedBy(party)\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-represented\">{{ label('representedBy') }}: {{ representedBy(party) }}</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"correspondenceOf(party)\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-parties__muted\"\n\t\t\t\t\t\t\t\t:data-party-documents=\"party.partyUuid || party.contactUid\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-documents\">{{ correspondenceOf(party) }}</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-for=\"indicator in indicatorsFor(party)\"\n\t\t\t\t\t\t\t\t:key=\"`${party.partyUuid}-${indicator.key}`\"\n\t\t\t\t\t\t\t\tclass=\"cn-status-badge cn-status-badge--default\"\n\t\t\t\t\t\t\t\t:class=\"`cn-object-parties__indicator--${indicator.severity}`\"\n\t\t\t\t\t\t\t\t:data-effect=\"indicator.effect\"\n\t\t\t\t\t\t\t\t:title=\"indicator.verdict\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-indicator\">{{ indicator.label }} · {{ indicator.verdict }}</span>\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tv-if=\"canRemove && party.partyUuid\"\n\t\t\t\t\t\t\t\tclass=\"cn-object-parties__remove\"\n\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\t:aria-label=\"removeLabel(party, group)\"\n\t\t\t\t\t\t\t\t:title=\"removeLabel(party, group)\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-object-parties-remove\"\n\t\t\t\t\t\t\t\t@click=\"removing = { party, group }\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<TrashCanOutline :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\t\t</template>\n\n\t\t<CnPartyAddDialog\n\t\t\tv-if=\"adding\"\n\t\t\tref=\"addDialog\"\n\t\t\t:dialogTitle=\"manageWord('add', 'dialogTitle', t('nextcloud-vue', 'Add a party'))\"\n\t\t\t:roles=\"addRoles\"\n\t\t\t:sources=\"addSources\"\n\t\t\t:createFields=\"createFields\"\n\t\t\t:createLabel=\"manageWord('add', 'createLabel', t('nextcloud-vue', 'Someone new'))\"\n\t\t\t:allowPrimary=\"content.manage.add.primary === true\"\n\t\t\t:primaryLabel=\"label('primary')\"\n\t\t\t:confirmLabel=\"manageWord('add', 'confirmLabel', t('nextcloud-vue', 'Add'))\"\n\t\t\t@close=\"adding = false\"\n\t\t\t@confirm=\"addParty\" />\n\n\t\t<CnConfirmDialog\n\t\t\tv-if=\"removing\"\n\t\t\tref=\"removeDialog\"\n\t\t\t:dialogTitle=\"manageWord('remove', 'title', t('nextcloud-vue', 'Remove party'))\"\n\t\t\t:message=\"removeMessage\"\n\t\t\t:confirmLabel=\"manageWord('remove', 'confirmLabel', t('nextcloud-vue', 'Remove'))\"\n\t\t\tvariant=\"error\"\n\t\t\t@close=\"removing = null\"\n\t\t\t@confirm=\"removeParty\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport EmailOutline from 'vue-material-design-icons/EmailOutline.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport TrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'\nimport CnConfirmDialog from '../../dialogs/CnConfirmDialog.vue'\nimport CnPartyAddDialog from '../../dialogs/CnPartyAddDialog.vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { normalizeLook } from '../../composables/useLook.js'\nimport innerHeading from '../../mixins/innerHeading.js'\nimport { conditionalLine } from '../../utils/conditionalLine.js'\nimport { initialsOf } from '../../utils/initials.js'\nimport {\n\tdocumentsOfParty,\n\tindicatorsOf,\n\tindicatorVerdict,\n\tkindCode,\n\tnewPartyRecord,\n\trepresentedByMap,\n\troleLabel,\n\trolesInOrder,\n\tsavedUuid,\n} from '../../utils/objectParties.js'\nimport { fetchCallerScope } from '../../utils/objectPermissions.js'\nimport { readPath } from '../../utils/readPath.js'\n\nlet uid = 0\n\n/**\n * The default words, keyed as `content.labels` overrides them.\n *\n * @return {object} The labels.\n */\nfunction defaultLabels() {\n\treturn {\n\t\tfailed: t('nextcloud-vue', 'The parties could not be read'),\n\t\tfailedDetail: t('nextcloud-vue', 'OpenRegister did not answer. Nothing has been removed.'),\n\t\tempty: t('nextcloud-vue', 'No parties yet'),\n\t\temptyDetail: t('nextcloud-vue', 'Add a party to record who this is for and who acts on it.'),\n\t\taccepted: t('nextcloud-vue', 'Accepted kinds'),\n\t\tprimary: t('nextcloud-vue', 'Primary party'),\n\t\tnotAccepted: t('nextcloud-vue', 'Kind not accepted here'),\n\t\trepresentedBy: t('nextcloud-vue', 'Represented by'),\n\t\tnoPrimary: t('nextcloud-vue', 'No main contact yet'),\n\t}\n}\n\n/**\n * CnObjectPartiesWidget — the `parties` widget: a record's parties as\n * OpenRegister's party model answers them, grouped by role with the primary\n * party first. Each party shows its kind, its representative and the\n * indicators on it, each with its verdict. A blocking verdict is also a note\n * above the list, so nobody publishes or sends past it.\n *\n * ```json\n * {\n * \"type\": \"parties\",\n * \"content\": {\n * \"rolesObjects\": { \"register\": \"myapp\", \"schema\": \"role\", \"field\": \"item\" },\n * \"roleLabels\": { \"applicant\": \"Applicant\" },\n * \"kindsSource\": { \"url\": \"/apps/myapp/api/items/@objectId/party-kinds\", \"enforce\": \"crm\" },\n * \"extraLines\": [{ \"endpoint\": \"/apps/myapp/api/items/@objectId/parties/{party}/language\", \"lines\": [\"Language: {language}\"] }],\n * \"correspondence\": { \"endpoint\": \"/apps/myapp/api/items/@objectId/documents\", \"path\": \"documents\" }\n * }\n * }\n * ```\n *\n * `manage` lets a reader change the parties through OpenRegister's party\n * API, which asks the record's update right on every write: `add` (`{ label?,\n * dialogTitle?, kind?, sources, create?, primary?, confirmLabel? }`) opens a\n * dialog to pick somebody known or describe somebody new (`create: {\n * register, schema, label?, fields, compose? }`, see `newPartyRecord`), choose\n * a role and optionally make them the primary party; `remove` (`{ title?,\n * message?, confirmLabel? }`, `{name}` and `{role}` in the message) takes a\n * party off in one role. Both are hidden when OpenRegister says the reader\n * may not update the schema; a refusal is shown, never swallowed.\n *\n * `presentation: \"primary\"` draws only the primary party, as a side card\n * does: initials, name and role label, its correspondence e-mail, and\n * `link` (`{ label, href? | tab? }`, `{total}` = the number of parties) at\n * the foot; `tab` opens that tab of the page through the route hash. It\n * reads the listing only.\n *\n * A failed read says so and is never shown as \"no parties\".\n *\n * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-shows-its-parties-by-role\n */\nexport default {\n\tname: 'CnObjectPartiesWidget',\n\n\tcomponents: { CnConfirmDialog, CnPartyAddDialog, EmailOutline, NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard, Plus, TrashCanOutline },\n\n\tmixins: [innerHeading],\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t\tcnLook: { default: 'nextcloud' },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The configuration: `rolesSource` (the listing URL, default\n\t\t * OpenRegister's `/parties` of this record), `partySource` (one\n\t\t * party, `{uuid}` filled in), `rolesObjects` (`{ register, schema,\n\t\t * field }`, the role rows that say who represents whom), `roleLabels`,\n\t\t * `kindsSource` (`{ url, enforce?, sourceText? }`), `extraLines`\n\t\t * (`[{ endpoint, path?, valueLabels?, lines }]`, one request per\n\t\t * party, `{party}` filled in), `correspondence` (`{ endpoint, path?,\n\t\t * senderField?, recipientsField? }`), `labels`, `presentation`\n\t\t * (`\"primary\"`: only the primary party) and `link` (`{ label,\n\t\t * href? | tab? }`, the primary presentation's foot link) and\n\t\t * `manage` (`{ add?, remove? }`, adding and removing parties).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, bound by the detail host. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's register slug. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's schema slug. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\tuid += 1\n\t\treturn {\n\t\t\tidPrefix: `cn-object-parties-${uid}`,\n\t\t\tloading: true,\n\t\t\tfailed: false,\n\t\t\tlisting: null,\n\t\t\tpartyRecords: {},\n\t\t\trepresented: {},\n\t\t\tkinds: null,\n\t\t\textra: {},\n\t\t\tdocuments: [],\n\t\t\tmayUpdate: true,\n\t\t\tadding: false,\n\t\t\tremoving: null,\n\t\t\tmanageError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {boolean} The board look draws one ruled row per party. */\n\t\tisBoard() {\n\t\t\treturn normalizeLook(this.cnLook) === 'board'\n\t\t},\n\n\t\t/** @return {Array<object>} The role groups, primary first. */\n\t\tgroups() {\n\t\t\treturn rolesInOrder(this.listing, this.translatedMap(this.content?.roleLabels))\n\t\t},\n\n\t\t/** @return {object} The `manage` declaration, or an empty one. */\n\t\tmanage() {\n\t\t\tconst manage = this.content?.manage\n\t\t\treturn manage && typeof manage === 'object' ? manage : {}\n\t\t},\n\n\t\t/** @return {boolean} Whether the add button shows. */\n\t\tcanAdd() {\n\t\t\treturn Boolean(this.manage.add) && this.mayUpdate && !this.isPrimaryPresentation && !this.loading && !this.failed\n\t\t},\n\n\t\t/** @return {boolean} Whether each party offers its remove button. */\n\t\tcanRemove() {\n\t\t\treturn Boolean(this.manage.remove) && this.mayUpdate && !this.isPrimaryPresentation\n\t\t},\n\n\t\t/** @return {Array<{key: string, label: string}>} The roles a new party may hold, in the reader's words. */\n\t\taddRoles() {\n\t\t\tconst declared = Array.isArray(this.listing?.roles) ? this.listing.roles : []\n\t\t\tconst kind = this.manage.add?.kind\n\t\t\tconst accepted = kind ? (this.listing?.kinds || []).find((entry) => kindCode(entry) === kind)?.roles : null\n\t\t\tconst keys = Array.isArray(accepted) && accepted.length > 0 ? accepted : declared.map((role) => role?.key).filter(Boolean)\n\t\t\tconst own = this.translatedMap(this.content?.roleLabels)\n\t\t\treturn keys.map((key) => ({ key, label: own[key] || this.cnTranslate(roleLabel(key, declared, {})) }))\n\t\t},\n\n\t\t/** @return {Array<object>} The picker sources, their words translated by the picker. */\n\t\taddSources() {\n\t\t\treturn Array.isArray(this.manage.add?.sources) ? this.manage.add.sources : []\n\t\t},\n\n\t\t/** @return {Array<object>} The new-person fields, labels translated. */\n\t\tcreateFields() {\n\t\t\tconst fields = this.manage.add?.create?.fields\n\t\t\treturn (Array.isArray(fields) ? fields : [])\n\t\t\t\t.filter((field) => field && field.key)\n\t\t\t\t.map((field) => ({ ...field, label: this.cnTranslate(field.label || field.key) }))\n\t\t},\n\n\t\t/** @return {string} The question the remove dialog asks. */\n\t\tremoveMessage() {\n\t\t\tif (!this.removing) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst name = this.nameOf(this.removing.party)\n\t\t\tconst role = this.removing.group.label\n\t\t\tconst own = this.manage.remove?.message\n\t\t\treturn own\n\t\t\t\t? this.cnTranslate(own).replaceAll('{name}', name).replaceAll('{role}', role)\n\t\t\t\t: t('nextcloud-vue', 'Remove {name} as {role}?', { name, role }, undefined, { escape: false })\n\t\t},\n\n\t\t/** @return {boolean} Whether only the primary party is drawn. */\n\t\tisPrimaryPresentation() {\n\t\t\treturn this.content?.presentation === 'primary'\n\t\t},\n\n\t\t/** @return {object|null} The primary party's listing row. */\n\t\tmainParty() {\n\t\t\tif (!this.primary) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (this.listing?.results || []).find((row) => row && row.partyUuid === this.primary) || null\n\t\t},\n\n\t\t/** @return {string} The primary party's role, in the app's words. */\n\t\tmainRole() {\n\t\t\tconst key = this.mainParty?.role\n\t\t\tif (!key) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst own = this.translatedMap(this.content?.roleLabels)\n\t\t\tif (typeof own[key] === 'string' && own[key] !== '') {\n\t\t\t\treturn own[key]\n\t\t\t}\n\t\t\treturn this.cnTranslate(roleLabel(key, this.listing?.roles, {}))\n\t\t},\n\n\t\t/** @return {{label: string, href: string}|null} The primary presentation's foot link; none without parties. */\n\t\tfootLink() {\n\t\t\tconst link = this.content?.link\n\t\t\tconst total = Number(this.listing?.total ?? (this.listing?.results || []).length)\n\t\t\tif (!link || typeof link !== 'object' || !link.label || !(total > 0)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst href = link.tab ? `#${encodeURIComponent(link.tab)}` : (link.href || '')\n\t\t\tif (href === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { label: this.cnTranslate(link.label).replaceAll('{total}', String(total)), href }\n\t\t},\n\n\t\t/** @return {string|null} The primary party's uuid. */\n\t\tprimary() {\n\t\t\treturn this.listing?.primary || null\n\t\t},\n\n\t\t/** @return {object} The verdict words, translated. */\n\t\tverdictLabels() {\n\t\t\tconst own = this.content?.labels || {}\n\t\t\tconst out = {}\n\t\t\tfor (const key of ['verdictPublication', 'verdictSend', 'verdictWarn']) {\n\t\t\t\tif (typeof own[key] === 'string' && own[key] !== '') {\n\t\t\t\t\tout[key] = this.cnTranslate(own[key])\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/** @return {Array<object>} The blocking verdicts, as notes above the list. */\n\t\tverdicts() {\n\t\t\treturn indicatorsOf(Object.values(this.partyRecords))\n\t\t\t\t.map((indicator) => ({\n\t\t\t\t\t...indicatorVerdict(indicator, this.verdictLabels),\n\t\t\t\t\tparty: indicator.party,\n\t\t\t\t\tkey: indicator.key,\n\t\t\t\t\tsentence: this.sentenceFor(indicator),\n\t\t\t\t}))\n\t\t\t\t.filter((verdict) => verdict.severity === 'error')\n\t\t},\n\n\t\t/** @return {string} Where the accepted kinds come from. */\n\t\tkindsSourceText() {\n\t\t\tconst texts = this.content?.kindsSource?.sourceText\n\t\t\tif (!this.kinds || !texts || typeof texts !== 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst text = texts[this.kinds.source] || texts.default || ''\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\t/** @return {Record<string, string>} The kind labels the listing declares. */\n\t\tkindLabels() {\n\t\t\tconst labels = {}\n\t\t\tfor (const kind of this.listing?.kinds || []) {\n\t\t\t\tif (kind && kind.key) {\n\t\t\t\t\tlabels[kind.key] = kind.label || kind.key\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn labels\n\t\t},\n\n\t\t/** @return {string} A key that changes when the record does. */\n\t\trecordKey() {\n\t\t\treturn `${this.register}|${this.schema}|${this.objectId}`\n\t\t},\n\t},\n\n\twatch: {\n\t\trecordKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.onPageRefresh = (payload) => {\n\t\t\tif (payload?.source !== this.idPrefix) {\n\t\t\t\tthis.load()\n\t\t\t}\n\t\t}\n\t\tsubscribe('cn:page:refresh', this.onPageRefresh)\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.onPageRefresh)\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tinitialsOf,\n\t\tkindCode,\n\n\t\t/**\n\t\t * A label: the content's own (translated), else the default.\n\t\t *\n\t\t * @param {string} key The label key.\n\t\t * @return {string}\n\t\t */\n\t\tlabel(key) {\n\t\t\tconst own = this.content?.labels && typeof this.content.labels[key] === 'string' ? this.content.labels[key] : ''\n\t\t\treturn own !== '' ? this.cnTranslate(own) : defaultLabels()[key]\n\t\t},\n\n\t\t/**\n\t\t * A word of the `manage` declaration, translated, else the default.\n\t\t *\n\t\t * @param {string} part `add` or `remove`.\n\t\t * @param {string} key The word's key.\n\t\t * @param {string} fallback The default.\n\t\t * @return {string}\n\t\t */\n\t\tmanageWord(part, key, fallback) {\n\t\t\tconst own = this.manage[part]?.[key]\n\t\t\treturn typeof own === 'string' && own !== '' ? this.cnTranslate(own) : fallback\n\t\t},\n\n\t\t/**\n\t\t * The remove button's accessible name.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @param {object} group The role group.\n\t\t * @return {string}\n\t\t */\n\t\tremoveLabel(party, group) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as {role}', { name: this.nameOf(party), role: group.label }, undefined, { escape: false })\n\t\t},\n\n\t\t/**\n\t\t * Why a write failed, in the reader's words.\n\t\t *\n\t\t * @param {unknown} error The axios error.\n\t\t * @return {string}\n\t\t */\n\t\trefusalOf(error) {\n\t\t\tif (error?.response?.status === 403) {\n\t\t\t\treturn t('nextcloud-vue', 'You may not change who is on this record.')\n\t\t\t}\n\t\t\tconst said = error?.response?.data?.error\n\t\t\treturn typeof said === 'string' && said !== '' ? said : t('nextcloud-vue', 'The change could not be saved. Nothing was changed.')\n\t\t},\n\n\t\t/** @return {string} The record's parties URL. */\n\t\tpartiesUrl() {\n\t\t\treturn this.urlOf(this.content?.rolesSource || '/apps/openregister/api/objects/@register/@schema/@objectId/parties')\n\t\t},\n\n\t\t/** @return {Promise<void>} Whether OpenRegister lets the reader update this schema; unknown counts as yes, the server decides. */\n\t\tasync loadMayUpdate() {\n\t\t\tif (!this.manage.add && !this.manage.remove) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst slug = (value) => (value && typeof value === 'object' ? String(value.slug || value.id || '') : String(value || ''))\n\t\t\tconst scope = await fetchCallerScope({ register: slug(this.register), schema: slug(this.schema) })\n\t\t\tthis.mayUpdate = !scope || !Array.isArray(scope.actions) || scope.actions.includes('update')\n\t\t},\n\n\t\t/**\n\t\t * Create the person when they are new, then give them the role; a\n\t\t * primary party is set through the primary route, which records the\n\t\t * replacement.\n\t\t *\n\t\t * @param {{mode: string, partyUuid: string|null, values: object, role: string, primary: boolean}} choice The dialog's choice.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync addParty(choice) {\n\t\t\ttry {\n\t\t\t\tlet partyUuid = choice.partyUuid\n\t\t\t\tif (choice.mode === 'new') {\n\t\t\t\t\tconst create = this.manage.add?.create || {}\n\t\t\t\t\tconst { data } = await axios.post(\n\t\t\t\t\t\tgenerateUrl(`/apps/openregister/api/objects/${encodeURIComponent(create.register || '')}/${encodeURIComponent(create.schema || '')}`),\n\t\t\t\t\t\tnewPartyRecord(create, choice.values),\n\t\t\t\t\t)\n\t\t\t\t\tpartyUuid = savedUuid(data)\n\t\t\t\t\tif (partyUuid === '') {\n\t\t\t\t\t\tthrow new Error(t('nextcloud-vue', 'The new person was not saved.'))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (choice.primary) {\n\t\t\t\t\tawait axios.put(generateUrl(`${this.partiesUrl()}/primary`), { partyUuid, role: choice.role })\n\t\t\t\t} else {\n\t\t\t\t\tawait axios.post(generateUrl(this.partiesUrl()), { partyUuid, role: choice.role })\n\t\t\t\t}\n\t\t\t\tthis.adding = false\n\t\t\t\tthis.changed()\n\t\t\t} catch (error) {\n\t\t\t\tthis.$refs.addDialog?.fail(error?.response ? this.refusalOf(error) : (error?.message || this.refusalOf(error)))\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} Take the chosen party off in the chosen role. */\n\t\tasync removeParty() {\n\t\t\tconst { party, group } = this.removing || {}\n\t\t\tif (!party) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait axios.delete(generateUrl(`${this.partiesUrl()}/${encodeURIComponent(party.partyUuid)}`), { params: { role: group.key } })\n\t\t\t\tthis.removing = null\n\t\t\t\tthis.changed()\n\t\t\t} catch (error) {\n\t\t\t\tthis.$refs.removeDialog?.setResult({ error: this.refusalOf(error) })\n\t\t\t}\n\t\t},\n\n\t\t/** @return {void} Read the parties again and tell the page (tab counts, the side card). */\n\t\tchanged() {\n\t\t\tthis.manageError = ''\n\t\t\tthis.load()\n\t\t\temit('cn:page:refresh', { source: this.idPrefix })\n\t\t},\n\n\t\t/**\n\t\t * A map of manifest words, translated.\n\t\t *\n\t\t * @param {object} map The map.\n\t\t * @return {Record<string, string>}\n\t\t */\n\t\ttranslatedMap(map) {\n\t\t\tconst out = {}\n\t\t\tfor (const [key, value] of Object.entries(map && typeof map === 'object' ? map : {})) {\n\t\t\t\tout[key] = typeof value === 'string' ? this.cnTranslate(value) : value\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * An app path with the record's tokens and `{party}` filled in.\n\t\t *\n\t\t * @param {string} template The path.\n\t\t * @param {string} [party] A party uuid.\n\t\t * @return {string}\n\t\t */\n\t\turlOf(template, party = '') {\n\t\t\tconst withSlugs = String(template)\n\t\t\t\t.replaceAll('@register', String(this.register || ''))\n\t\t\t\t.replaceAll('@schema', String(this.schema || ''))\n\t\t\treturn interpolateUrlTokens(withSlugs, { objectId: this.objectId }).replaceAll('{party}', encodeURIComponent(party)).replaceAll('{uuid}', encodeURIComponent(party))\n\t\t},\n\n\t\t/**\n\t\t * GET an app path; null when it fails.\n\t\t *\n\t\t * @param {string} path The app path.\n\t\t * @param {object} [params] Query parameters.\n\t\t * @return {Promise<unknown>}\n\t\t */\n\t\tasync read(path, params) {\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.get(generateUrl(path), params ? { params } : undefined)\n\t\t\t\treturn data ?? null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the listing, then each party, the representation, the kinds,\n\t\t * the extra lines and the correspondence.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.objectId) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\tthis.partyRecords = {}\n\t\t\tthis.represented = {}\n\t\t\tthis.extra = {}\n\t\t\tthis.documents = []\n\t\t\tconst listing = await this.read(this.urlOf(this.content?.rolesSource || '/apps/openregister/api/objects/@register/@schema/@objectId/parties'))\n\t\t\tif (!listing || typeof listing !== 'object') {\n\t\t\t\tthis.failed = true\n\t\t\t\tthis.listing = null\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.listing = listing\n\t\t\tawait this.loadMayUpdate()\n\t\t\tif (this.isPrimaryPresentation) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst uuids = [...new Set((listing.results || []).map((row) => row && row.partyUuid).filter(Boolean))]\n\t\t\tconst partyUrl = this.content?.partySource || '/apps/openregister/api/parties/{uuid}'\n\t\t\tconst records = await Promise.all(uuids.map((uuid) => this.read(this.urlOf(partyUrl, uuid))))\n\t\t\tconst byUuid = {}\n\t\t\tuuids.forEach((uuid, index) => {\n\t\t\t\tif (records[index] && typeof records[index] === 'object') {\n\t\t\t\t\tbyUuid[uuid] = records[index]\n\t\t\t\t}\n\t\t\t})\n\t\t\tthis.partyRecords = byUuid\n\t\t\tawait Promise.all([this.loadRepresentation(), this.loadKinds(), this.loadExtraLines(uuids), this.loadCorrespondence()])\n\t\t\tthis.loading = false\n\t\t},\n\n\t\t/** @return {Promise<void>} Who represents whom, from the role rows. */\n\t\tasync loadRepresentation() {\n\t\t\tconst source = this.content?.rolesObjects\n\t\t\tif (!source || !source.register || !source.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(`/apps/openregister/api/objects/${encodeURIComponent(source.register)}/${encodeURIComponent(source.schema)}`, { [source.field || 'object']: String(this.objectId), _limit: 200 })\n\t\t\tconst rows = Array.isArray(data?.results) ? data.results : (Array.isArray(data) ? data : [])\n\t\t\tthis.represented = representedByMap(rows)\n\t\t},\n\n\t\t/** @return {Promise<void>} The kinds this record accepts. */\n\t\tasync loadKinds() {\n\t\t\tconst source = this.content?.kindsSource\n\t\t\tthis.kinds = null\n\t\t\tif (!source || !source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(this.urlOf(source.url))\n\t\t\tthis.kinds = data && Array.isArray(data.kinds) ? data : null\n\t\t},\n\n\t\t/**\n\t\t * One answer per party per extra line.\n\t\t *\n\t\t * @param {Array<string>} uuids The parties.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadExtraLines(uuids) {\n\t\t\tconst lines = Array.isArray(this.content?.extraLines) ? this.content.extraLines : []\n\t\t\tconst extra = {}\n\t\t\tawait Promise.all(lines.map(async (spec, index) => {\n\t\t\t\tif (!spec || !spec.endpoint) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst answers = await Promise.all(uuids.map((uuid) => this.read(this.urlOf(spec.endpoint, uuid))))\n\t\t\t\tuuids.forEach((uuid, i) => {\n\t\t\t\t\tconst answer = spec.path ? readPath(answers[i], spec.path) : answers[i]\n\t\t\t\t\tif (answer && typeof answer === 'object') {\n\t\t\t\t\t\textra[`${index}|${uuid}`] = answer\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}))\n\t\t\tthis.extra = extra\n\t\t},\n\n\t\t/** @return {Promise<void>} The documents the correspondence counts read. */\n\t\tasync loadCorrespondence() {\n\t\t\tconst spec = this.content?.correspondence\n\t\t\tif (!spec || !spec.endpoint) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = await this.read(this.urlOf(spec.endpoint))\n\t\t\tconst list = spec.path ? readPath(data, spec.path) : data\n\t\t\tthis.documents = Array.isArray(list) ? list : []\n\t\t},\n\n\t\t/**\n\t\t * The extra lines for a party, each the first of its `lines` that applies.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {Array<string>}\n\t\t */\n\t\textraLinesOf(party) {\n\t\t\tconst specs = Array.isArray(this.content?.extraLines) ? this.content.extraLines : []\n\t\t\treturn specs.map((spec, index) => {\n\t\t\t\tconst answer = this.extra[`${index}|${party.partyUuid}`]\n\t\t\t\tif (!answer) {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn conditionalLine(spec.lines || [], this.labelled(answer, spec.valueLabels), (text) => this.cnTranslate(text))\n\t\t\t}).filter((line) => line !== '')\n\t\t},\n\n\t\t/**\n\t\t * An answer with its coded values replaced by their labels\n\t\t * (`valueLabels: { language: { nl: \"Dutch\" } }`; `nl-NL` reads as `nl`).\n\t\t *\n\t\t * @param {object} answer The answer.\n\t\t * @param {object} valueLabels The labels by field and value.\n\t\t * @return {object}\n\t\t */\n\t\tlabelled(answer, valueLabels) {\n\t\t\tif (!valueLabels || typeof valueLabels !== 'object') {\n\t\t\t\treturn answer\n\t\t\t}\n\t\t\tconst out = { ...answer }\n\t\t\tfor (const [field, map] of Object.entries(valueLabels)) {\n\t\t\t\tconst raw = answer[field]\n\t\t\t\tif (typeof raw !== 'string' || !map) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst hit = map[raw] ?? map[raw.toLowerCase().split('-')[0]]\n\t\t\t\tif (typeof hit === 'string') {\n\t\t\t\t\tout[field] = this.cnTranslate(hit)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Whether a party's kind is one this record does not accept. Only when\n\t\t * the kinds come from the source named by `kindsSource.enforce`.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {boolean}\n\t\t */\n\t\tnotAccepted(party) {\n\t\t\tconst enforce = this.content?.kindsSource?.enforce\n\t\t\tif (!party?.partyKind || !this.kinds || (enforce && this.kinds.source !== enforce)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !this.kinds.kinds.some((kind) => kindCode(kind) === party.partyKind)\n\t\t},\n\n\t\t/**\n\t\t * A party's kind: the accepted kind's label, else the listing's, else the code.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tkindOf(party) {\n\t\t\tif (!party.partyKind) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst offered = (this.kinds?.kinds || []).find((kind) => kindCode(kind) === party.partyKind)\n\t\t\treturn offered?.label || this.kindLabels[party.partyKind] || party.partyKind\n\t\t},\n\n\t\t/**\n\t\t * Who represents this party, by name.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\trepresentedBy(party) {\n\t\t\tconst uuid = this.represented[party.partyUuid || party.contactUid || ''] || ''\n\t\t\tif (uuid === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst row = (this.listing?.results || []).find((candidate) => candidate?.partyUuid === uuid)\n\t\t\treturn row ? this.nameOf(row) : (this.partyRecords[uuid]?.name || uuid)\n\t\t},\n\n\t\t/**\n\t\t * A party's name: the listing's, else the party record's, else its id.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tnameOf(party) {\n\t\t\treturn party.displayName || this.partyRecords[party.partyUuid]?.name || party.contactUid || party.partyUuid || ''\n\t\t},\n\n\t\t/**\n\t\t * How many documents a party sent and received.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {string}\n\t\t */\n\t\tcorrespondenceOf(party) {\n\t\t\tconst spec = this.content?.correspondence || {}\n\t\t\tconst { sent, received } = documentsOfParty(this.documents, party.partyUuid || party.contactUid || '', spec)\n\t\t\tif (sent.length === 0 && received.length === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (received.length === 0) {\n\t\t\t\treturn n('nextcloud-vue', '%n document sent', '%n documents sent', sent.length)\n\t\t\t}\n\t\t\tif (sent.length === 0) {\n\t\t\t\treturn n('nextcloud-vue', '%n document received', '%n documents received', received.length)\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{sent} sent, {received} received', { sent: sent.length, received: received.length })\n\t\t},\n\n\t\t/**\n\t\t * The indicators on a party, each with its verdict.\n\t\t *\n\t\t * @param {object} party The listing row.\n\t\t * @return {Array<object>}\n\t\t */\n\t\t/**\n\t\t * The board row's meta line: the primary mark, the role, the kind,\n\t\t * whom the party represents, its extra lines, e-mail and documents,\n\t\t * separated by middots.\n\t\t *\n\t\t * @param {object} party The party.\n\t\t * @param {object} group Its role group.\n\t\t * @return {string}\n\t\t */\n\t\tboardMetaOf(party, group) {\n\t\t\tconst parts = []\n\t\t\tif (this.primary && party.partyUuid === this.primary) {\n\t\t\t\tparts.push(this.label('primary'))\n\t\t\t}\n\t\t\tparts.push(group.label, this.kindOf(party))\n\t\t\tconst represented = this.representedBy(party)\n\t\t\tif (represented) {\n\t\t\t\tparts.push(`${this.label('representedBy')}: ${represented}`)\n\t\t\t}\n\t\t\tparts.push(...this.extraLinesOf(party), party.email, this.correspondenceOf(party))\n\t\t\treturn parts.filter((part) => typeof part === 'string' && part !== '').join(' · ')\n\t\t},\n\n\t\tindicatorsFor(party) {\n\t\t\tconst record = this.partyRecords[party.partyUuid]\n\t\t\tif (!record) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn (record.indicators || []).filter(Boolean).map((indicator) => ({ ...indicatorVerdict(indicator, this.verdictLabels), key: indicator.key }))\n\t\t},\n\n\t\t/**\n\t\t * The sentence of a blocking verdict, naming the party.\n\t\t *\n\t\t * @param {object} indicator The indicator with `partyName`.\n\t\t * @return {string}\n\t\t */\n\t\tsentenceFor(indicator) {\n\t\t\tconst name = indicator.partyName || indicator.party\n\t\t\tconst own = this.content?.labels || {}\n\t\t\tif (indicatorVerdict(indicator).effect === 'refuse-publication') {\n\t\t\t\treturn own.sentencePublication\n\t\t\t\t\t? this.cnTranslate(own.sentencePublication).replaceAll('{party}', name)\n\t\t\t\t\t: t('nextcloud-vue', 'Publishing a file on this record is refused, because of {party}.', { party: name }, undefined, { escape: false })\n\t\t\t}\n\t\t\treturn own.sentenceSend\n\t\t\t\t? this.cnTranslate(own.sentenceSend).replaceAll('{party}', name)\n\t\t\t\t: t('nextcloud-vue', 'A message to {party} is refused.', { party: name }, undefined, { escape: false })\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-object-parties {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__verdicts {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline, 4px);\n}\n\n.cn-object-parties__role-label {\n\tmargin: 0 0 var(--default-grid-baseline, 4px) 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-object-parties__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--default-grid-baseline, 4px);\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-object-parties__party {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2);\n\tpadding: var(--default-grid-baseline, 4px);\n\tborder-radius: var(--border-radius, 4px);\n}\n\n.cn-object-parties__party:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-parties__name {\n\tfont-weight: bold;\n}\n\n.cn-object-parties__muted {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-object-parties__manage {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n}\n\n.cn-object-parties__remove {\n\tmargin-inline-start: auto;\n}\n\n.cn-object-parties__main-card {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__main {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 3);\n}\n\n.cn-object-parties__main-initials {\n\tdisplay: flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 40px;\n\theight: 40px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-weight: 700;\n}\n\n.cn-object-parties__main-text {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-object-parties__main-name {\n\tfont-size: 15px;\n}\n\n.cn-object-parties__main-role {\n\tfont-size: 13px;\n}\n\n.cn-object-parties__main-email {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2.5);\n\tcolor: var(--color-main-text);\n\toverflow-wrap: anywhere;\n}\n\n.cn-object-parties__main-link {\n\tcolor: var(--color-primary-element);\n\tfont-weight: 600;\n}\n\n.cn-object-parties__accepted {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: calc(var(--default-grid-baseline, 4px) * 2);\n\tpadding: calc(var(--default-grid-baseline, 4px) * 2) calc(var(--default-grid-baseline, 4px) * 3);\n\tborder-radius: var(--border-radius-large, 10px);\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-object-parties__accepted-label {\n\tfont-weight: 600;\n}\n\n.cn-object-parties__accepted-kind {\n\tborder: 1px solid var(--color-border-dark);\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_toDisplayString","_createBlock","_openBlock","_createElementBlock","_createElementVNode","_createTextVNode","_Fragment","_renderList","_resolveDynamicComponent"],"mappings":"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"}
@@ -2,7 +2,7 @@ import script from './CnRetentionWidget.vue2.js';
2
2
  import { render } from './CnRetentionWidget.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-5415dbb4";
5
+ script.__scopeId = "data-v-912351be";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -1 +1 @@
1
- {"version":3,"file":"CnRetentionWidget.vue2.js","sources":["../../../../src/components/CnRetentionWidget/CnRetentionWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-retention\" data-testid=\"cn-retention\">\n\t\t<header class=\"cn-retention__head\">\n\t\t\t<div class=\"cn-retention__head-text\">\n\t\t\t\t<h3 class=\"cn-retention__title\">\n\t\t\t\t\t{{ text(content.title) || t('nextcloud-vue', 'Archiving') }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-retention__muted\">\n\t\t\t\t\t{{ text(content.subtitle) || t('nextcloud-vue', 'What happens to this record once it is closed') }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<!-- Recompute starts in the header (board DqZaakArchivering); the\n\t\t\t dialog asks for the reason OpenRegister records with it. -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"content.recompute !== false && !loading && !error\"\n\t\t\t\t:disabled=\"!mayRecompute || busy\"\n\t\t\t\t:title=\"mayRecompute ? undefined : t('nextcloud-vue', 'Recomputing needs the archivist role')\"\n\t\t\t\t:aria-description=\"mayRecompute ? undefined : t('nextcloud-vue', 'Recomputing needs the archivist role')\"\n\t\t\t\t:data-testid=\"mayRecompute ? 'cn-retention-recompute-open' : 'cn-retention-recompute-denied'\"\n\t\t\t\t@click=\"recomputeOpen = true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Refresh :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Recompute nomination') }}\n\t\t\t</NcButton>\n\t\t</header>\n\t\t<CnRetentionRecomputeDialog\n\t\t\tv-if=\"recomputeOpen\"\n\t\t\t:user=\"currentUid\"\n\t\t\t:busy=\"busy\"\n\t\t\t@close=\"recomputeOpen = false\"\n\t\t\t@confirm=\"recompute\" />\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"24\" />\n\t\t<NcEmptyContent v-else-if=\"error\"\n\t\t\t:name=\"t('nextcloud-vue', 'The archival facts are unavailable')\"\n\t\t\t:description=\"error\"\n\t\t\tdata-testid=\"cn-retention-error\">\n\t\t\t<template #action>\n\t\t\t\t<NcButton data-testid=\"cn-retention-retry\" @click=\"load\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Try again') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\n\t\t<template v-else>\n\t\t\t<p v-if=\"archived\" class=\"cn-retention__archived\" data-testid=\"cn-retention-archived\">\n\t\t\t\t{{ t('nextcloud-vue', 'Archived on {at} by {by}. {reason}', { at: String(archived.at ?? ''), by: String(archived.by ?? ''), reason: String(archived.reason ?? '') }) }}\n\t\t\t</p>\n\t\t\t<NcNoteCard v-if=\"disagrees\" type=\"warning\" data-testid=\"cn-retention-disagreement\">\n\t\t\t\t{{ t('nextcloud-vue', 'This record and OpenRegister do not agree on whether it is archived.') }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<NcNoteCard v-if=\"nomination && nomination.status === 'unnominatable'\" type=\"warning\" data-testid=\"cn-retention-unnominatable\">\n\t\t\t\t{{ t('nextcloud-vue', 'Nothing could decide what happens to this record.') }}\n\t\t\t\t{{ String(nomination.unnominatableReason ?? '') }}\n\t\t\t</NcNoteCard>\n\t\t\t<div v-else-if=\"!nomination\" data-testid=\"cn-retention-pending\">\n\t\t\t\t<dl class=\"cn-retention__facts\">\n\t\t\t\t\t<div v-for=\"fact in pendingFacts\" :key=\"fact.key\" class=\"cn-retention__fact\">\n\t\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t\t<dd>{{ fact.value }}</dd>\n\t\t\t\t\t</div>\n\t\t\t\t</dl>\n\t\t\t\t<NcNoteCard type=\"info\">\n\t\t\t\t\t{{ text(content.pendingNote) || t('nextcloud-vue', 'This record has not been closed yet. Its archival future is recorded when it closes.') }}\n\t\t\t\t</NcNoteCard>\n\t\t\t</div>\n\t\t\t<dl v-else class=\"cn-retention__facts\" data-testid=\"cn-retention-facts\">\n\t\t\t\t<div v-for=\"fact in facts\" :key=\"fact.key\" class=\"cn-retention__fact\">\n\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t<dd :data-testid=\"`cn-retention-${fact.key}`\">\n\t\t\t\t\t\t{{ fact.value }}\n\t\t\t\t\t</dd>\n\t\t\t\t</div>\n\t\t\t</dl>\n\n\t\t\t<section v-if=\"content.legalHold\" class=\"cn-retention__section\" data-testid=\"cn-retention-hold\">\n\t\t\t\t<component :is=\"innerHeadingTag\" class=\"cn-inner-heading\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Kept for a procedure') }}\n\t\t\t\t</component>\n\t\t\t\t<ul class=\"cn-retention__rows\">\n\t\t\t\t\t<li v-for=\"hold in holds\" :key=\"hold.id\" class=\"cn-retention__row\">\n\t\t\t\t\t\t<span class=\"cn-retention__row-text\">\n\t\t\t\t\t\t\t<span class=\"cn-retention__row-title\">{{ hold.reason || t('nextcloud-vue', 'Legal hold') }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-retention__muted\">{{ t('nextcloud-vue', 'Placed on {date} by {by}', { date: hold.placedDate, by: hold.placedBy }) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<CnStatusBadge :label=\"t('nextcloud-vue', 'Active')\" variant=\"warning\" />\n\t\t\t\t\t</li>\n\t\t\t\t\t<li v-if=\"holds.length === 0\" class=\"cn-retention__row\">\n\t\t\t\t\t\t<span class=\"cn-retention__row-text\">\n\t\t\t\t\t\t\t<span class=\"cn-retention__row-title\">{{ t('nextcloud-vue', 'No legal hold') }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-retention__muted\">{{ t('nextcloud-vue', 'If an objection or appeal runs, destruction is suspended') }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<CnStatusBadge :label=\"t('nextcloud-vue', 'None')\" />\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\n\t\t\t<section v-if=\"content.transfer\" class=\"cn-retention__section\" data-testid=\"cn-retention-transfer\">\n\t\t\t\t<component :is=\"innerHeadingTag\" class=\"cn-inner-heading\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Transfer to the e-Depot') }}\n\t\t\t\t</component>\n\t\t\t\t<ul class=\"cn-retention__rows\">\n\t\t\t\t\t<li class=\"cn-retention__row\">\n\t\t\t\t\t\t<span class=\"cn-retention__row-text\">\n\t\t\t\t\t\t\t<span class=\"cn-retention__row-title\">{{ transfers ? t('nextcloud-vue', 'Goes to the e-Depot') : t('nextcloud-vue', 'Not applicable') }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-retention__muted\">{{ transfers ? t('nextcloud-vue', 'After the retention period the record is transferred') : t('nextcloud-vue', 'Only records appraised to keep go to the e-Depot') }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<CnStatusBadge :label=\"transfers ? t('nextcloud-vue', 'Transfer') : t('nextcloud-vue', 'No transfer')\" :variant=\"transfers ? 'info' : 'default'\" />\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\n\t\t\t<div v-if=\"outcome\" class=\"cn-retention__outcome\" data-testid=\"cn-retention-outcome\">\n\t\t\t\t<component :is=\"innerHeadingTag\" class=\"cn-inner-heading\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Outcome') }}\n\t\t\t\t</component>\n\t\t\t\t<p>{{ t('nextcloud-vue', 'Handed over as {kind} on {at} by {by}.', { kind: String(outcome.kind ?? ''), at: String(outcome.at ?? ''), by: String(outcome.by ?? '') }) }}</p>\n\t\t\t\t<p v-if=\"outcome.transferListUuid\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Transfer list') }}: {{ outcome.transferListUuid }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport CnRetentionRecomputeDialog from './CnRetentionRecomputeDialog.vue'\nimport innerHeading from '../../mixins/innerHeading.js'\nimport { parseDuration } from '../../utils/isoDuration.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { hasUnresolvedTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\n\n/**\n * CnRetentionWidget — the `retention` detail widget: what happens to a\n * record when its business use ends, as OpenRegister decided it. Every value\n * is read off the record's `@self._retention` (appraisal, disposal date,\n * retention period, selection list row, the rule and when it was written)\n * and `@self.archived`; the widget derives nothing, so it can never disagree\n * with the stored decision. A failed read is an error with a retry, never an\n * empty block. A record nothing could nominate is drawn apart from one that\n * is not closed yet. An archivist (or an admin) may ask OpenRegister to\n * recompute the nomination, with a reason. Any app on OpenRegister uses it;\n * dossiq's case Archiving tab is the first.\n *\n * `content`:\n * - `title`, `subtitle`: texts, through the host translate.\n * - `statusField`, `archivedValues`: a record field and the values that mean\n * archived (`archiveStatus`, `[\"archived\", ...]`); when set, a mismatch with\n * `@self.archived` is said out loud.\n * - `archivistGroups`: groups that may recompute (default `[\"archivaris\"]`;\n * admins always may); `recompute: false` hides the control.\n * - `expected`: before the record closes, the outcome its type expects.\n * `source: { register, schema, filter }` lists the candidate rules (a case\n * type's result types, `filter` tokens such as `@object.caseType`\n * resolved against the record); `fields: { appraisal, period,\n * selectionListRow }` names their fields; `appraisalLabels` names the\n * appraisal values; `periodText` writes the period (`{period} after the\n * decision`); `decidedBy` says who decides. When the candidates agree the\n * facts show that outcome, otherwise \"Depends on the result\". A failed\n * read keeps the plain facts.\n * - `pendingNote`: the note under the facts of a record not closed yet.\n * - `legalHold: true`: a section with the record's active legal holds\n * (`@self._retention.legalHold.holds`), or that none applies.\n * - `transfer: { keepValues }`: a section saying whether the record goes to\n * the e-Depot, from the stored or expected appraisal.\n *\n * The record is read fresh from OpenRegister by `register`, `schema` and\n * `objectId` (props, else the bound record's `@self`).\n */\nexport default {\n\tname: 'CnRetentionWidget',\n\n\tcomponents: { CnRetentionRecomputeDialog, CnStatusBadge, NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard, Refresh },\n\n\tmixins: [innerHeading],\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The bound record, on a detail page.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The record's register (else the bound record's `@self.register`). */\n\t\tregister: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record's schema (else the bound record's `@self.schema`); a schema object gives its slug.\n\t\t *\n\t\t * @type {string|number|object}\n\t\t */\n\t\tschema: {\n\t\t\ttype: [String, Number, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's id (else the bound record's). */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: true,\n\t\t\terror: '',\n\t\t\trecord: null,\n\t\t\t/** Whether the recompute dialog is open. */\n\t\t\trecomputeOpen: false,\n\t\t\tbusy: false,\n\t\t\t/** The candidate rules `content.expected` reads, null until read or when unreadable. */\n\t\t\texpectedRows: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The bound record's `@self`. */\n\t\tboundSelf() {\n\t\t\treturn (this.objectData && this.objectData['@self']) || {}\n\t\t},\n\n\t\t/** @return {string} The record id. */\n\t\tid() {\n\t\t\treturn String(this.objectId || (this.objectData && this.objectData.id) || this.boundSelf.id || '')\n\t\t},\n\n\t\t/** @return {string} The register. */\n\t\tregisterRef() {\n\t\t\treturn String(this.register || this.boundSelf.register || '')\n\t\t},\n\n\t\t/** @return {string} The schema. */\n\t\tschemaRef() {\n\t\t\tconst s = this.schema || this.boundSelf.schema || ''\n\t\t\treturn String(typeof s === 'object' ? (s.slug || s.id || '') : s)\n\t\t},\n\n\t\t/** @return {object} The record's `@self`. */\n\t\tself() {\n\t\t\treturn (this.record && this.record['@self']) || {}\n\t\t},\n\n\t\t/** @return {object|null} OpenRegister's stored retention decision. */\n\t\tretention() {\n\t\t\treturn this.self._retention || null\n\t\t},\n\n\t\t/** @return {object|null} The nomination. */\n\t\tnomination() {\n\t\t\treturn (this.retention && this.retention.nomination) || null\n\t\t},\n\n\t\t/** @return {object|null} The hand-over outcome. */\n\t\toutcome() {\n\t\t\treturn (this.retention && this.retention.outcome) || null\n\t\t},\n\n\t\t/** @return {object|null} OpenRegister's archived marker. */\n\t\tarchived() {\n\t\t\treturn this.self.archived || null\n\t\t},\n\n\t\t/**\n\t\t * Whether the record's own field and the platform marker disagree.\n\t\t *\n\t\t * @spec openspec/changes/retention-widget/specs/retention-widget/spec.md#requirement-a-record-shows-its-stored-retention\n\t\t * @return {boolean}\n\t\t */\n\t\tdisagrees() {\n\t\t\tconst field = this.content.statusField\n\t\t\tif (!field || !this.record) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst values = Array.isArray(this.content.archivedValues) ? this.content.archivedValues.map(String) : ['archived']\n\t\t\tconst saysArchived = values.includes(String(readPath(this.record, field) ?? ''))\n\t\t\treturn saysArchived !== Boolean(this.archived)\n\t\t},\n\n\t\t/**\n\t\t * The stored facts that have a value, in reading order.\n\t\t *\n\t\t * @spec openspec/changes/retention-widget/specs/retention-widget/spec.md#requirement-a-record-shows-its-stored-retention\n\t\t * @return {Array<{key: string, label: string, value: string}>}\n\t\t */\n\t\tfacts() {\n\t\t\tconst r = this.retention || {}\n\t\t\tconst n = this.nomination || {}\n\t\t\treturn [\n\t\t\t\t{ key: 'appraisal', label: t('nextcloud-vue', 'Appraisal'), value: r.appraisal },\n\t\t\t\t{ key: 'disposal-date', label: t('nextcloud-vue', 'Disposal date'), value: r.disposalDate },\n\t\t\t\t{ key: 'retention-period', label: t('nextcloud-vue', 'Retention period'), value: r.retentionPeriod },\n\t\t\t\t{ key: 'selection-list-row', label: t('nextcloud-vue', 'Selection list row'), value: r.selectionListRow },\n\t\t\t\t{ key: 'rule', label: t('nextcloud-vue', 'Decided by'), value: n.rule },\n\t\t\t\t{ key: 'decided-at', label: t('nextcloud-vue', 'Written on'), value: n.at },\n\t\t\t].filter((fact) => fact.value !== undefined && fact.value !== null && fact.value !== '').map((fact) => ({ ...fact, value: String(fact.value) }))\n\t\t},\n\n\t\t/**\n\t\t * The outcome the record's type expects before it closes: the agreed\n\t\t * appraisal, period and selection list row of the candidate rules, or\n\t\t * `mixed` when they disagree; null when nothing was read.\n\t\t *\n\t\t * @spec openspec/changes/retention-expected-outcome/specs/retention-widget/spec.md#requirement-an-open-record-shows-the-outcome-its-type-expects\n\t\t * @return {{appraisal: string, period: string, selectionListRow: string, mixed: boolean}|null}\n\t\t */\n\t\texpectedOutcome() {\n\t\t\tconst rows = this.expectedRows\n\t\t\tif (!Array.isArray(rows) || rows.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst fields = { appraisal: 'appraisal', period: 'period', selectionListRow: 'selectionListRow', ...(this.content.expected?.fields || {}) }\n\t\t\tconst pick = (row, key) => String(readPath(row, fields[key]) ?? '')\n\t\t\tconst outcomes = rows.map((row) => ({ appraisal: pick(row, 'appraisal'), period: pick(row, 'period'), selectionListRow: pick(row, 'selectionListRow') }))\n\t\t\tconst first = outcomes[0]\n\t\t\tconst agree = outcomes.every((o) => o.appraisal === first.appraisal && o.period === first.period)\n\t\t\tif (first.appraisal === '' && first.period === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn agree\n\t\t\t\t? { ...first, selectionListRow: outcomes.every((o) => o.selectionListRow === first.selectionListRow) ? first.selectionListRow : '', mixed: false }\n\t\t\t\t: { appraisal: '', period: '', selectionListRow: '', mixed: true }\n\t\t},\n\n\t\t/**\n\t\t * The facts of a record not closed yet: the expected outcome where the\n\t\t * type gives one, \"decided when it closes\" otherwise.\n\t\t *\n\t\t * @spec openspec/changes/retention-expected-outcome/specs/retention-widget/spec.md#requirement-an-open-record-shows-the-outcome-its-type-expects\n\t\t * @return {Array<{key: string, label: string, value: string}>}\n\t\t */\n\t\tpendingFacts() {\n\t\t\tconst atClosure = t('nextcloud-vue', 'Decided when it closes')\n\t\t\tconst expected = this.expectedOutcome\n\t\t\tif (!expected) {\n\t\t\t\treturn [\n\t\t\t\t\t{ key: 'appraisal', label: t('nextcloud-vue', 'Appraisal'), value: atClosure },\n\t\t\t\t\t{ key: 'retention-period', label: t('nextcloud-vue', 'Retention period'), value: atClosure },\n\t\t\t\t\t{ key: 'disposal-date', label: t('nextcloud-vue', 'Disposal date'), value: atClosure },\n\t\t\t\t\t{ key: 'decided-at', label: t('nextcloud-vue', 'Written on'), value: t('nextcloud-vue', 'Not yet') },\n\t\t\t\t]\n\t\t\t}\n\t\t\tconst depends = t('nextcloud-vue', 'Depends on the result')\n\t\t\tconst config = this.content.expected || {}\n\t\t\tconst facts = [\n\t\t\t\t{ key: 'appraisal', label: t('nextcloud-vue', 'Appraisal'), value: expected.mixed ? depends : this.appraisalLabel(expected.appraisal) },\n\t\t\t\t{ key: 'retention-period', label: t('nextcloud-vue', 'Retention period'), value: expected.mixed ? depends : this.periodLabel(expected.period) },\n\t\t\t]\n\t\t\tif (expected.selectionListRow) {\n\t\t\t\tfacts.push({ key: 'selection-list-row', label: t('nextcloud-vue', 'Selection list row'), value: expected.selectionListRow })\n\t\t\t}\n\t\t\tfacts.push({ key: 'disposal-date', label: t('nextcloud-vue', 'Disposal date'), value: atClosure })\n\t\t\tif (config.decidedBy) {\n\t\t\t\tfacts.push({ key: 'rule', label: t('nextcloud-vue', 'Decided by'), value: this.text(config.decidedBy) })\n\t\t\t}\n\t\t\tfacts.push({ key: 'decided-at', label: t('nextcloud-vue', 'Written on'), value: t('nextcloud-vue', 'Not yet') })\n\t\t\treturn facts.filter((fact) => fact.value !== '')\n\t\t},\n\n\t\t/** @return {Array<{id: string, reason: string, placedBy: string, placedDate: string}>} The active legal holds. */\n\t\tholds() {\n\t\t\tconst hold = (this.retention && this.retention.legalHold) || {}\n\t\t\tconst list = Array.isArray(hold.holds) ? hold.holds : []\n\t\t\treturn list.map((h, index) => ({ id: String(h.id ?? index), reason: String(h.reason ?? ''), placedBy: String(h.placedBy ?? ''), placedDate: String(h.placedDate ?? '') }))\n\t\t},\n\n\t\t/**\n\t\t * Whether the record goes to the e-Depot: its stored appraisal, else\n\t\t * the expected one, is one of `transfer.keepValues`.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\ttransfers() {\n\t\t\tconst keep = Array.isArray(this.content.transfer?.keepValues) ? this.content.transfer.keepValues.map(String) : ['bewaren', 'blijvend_bewaren', 'retain', 'keep']\n\t\t\tconst stored = this.retention && this.retention.appraisal\n\t\t\tconst appraisal = stored || (this.expectedOutcome && !this.expectedOutcome.mixed ? this.expectedOutcome.appraisal : '')\n\t\t\treturn keep.includes(String(appraisal || ''))\n\t\t},\n\n\t\t/** @return {string} The signed-in user's id. */\n\t\tcurrentUid() {\n\t\t\tconst user = getCurrentUser()\n\t\t\treturn String((user && user.uid) || '')\n\t\t},\n\n\t\t/**\n\t\t * Whether this user may recompute: an admin or an archivist group member.\n\t\t * Shown disabled otherwise, so the user learns which role it needs.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tmayRecompute() {\n\t\t\tconst user = getCurrentUser()\n\t\t\tif (user && user.isAdmin === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst groups = Array.isArray(user && user.groups) ? user.groups : []\n\t\t\tconst allowed = Array.isArray(this.content.archivistGroups) ? this.content.archivistGroups : ['archivaris']\n\t\t\treturn allowed.some((g) => groups.includes(g))\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * An appraisal value in words, through `expected.appraisalLabels`.\n\t\t *\n\t\t * @param {string} value The stored value.\n\t\t * @return {string}\n\t\t */\n\t\tappraisalLabel(value) {\n\t\t\tconst labels = this.content.expected?.appraisalLabels || {}\n\t\t\treturn labels[value] ? this.text(labels[value]) : value\n\t\t},\n\n\t\t/**\n\t\t * An ISO period in words (\"5 years\"), placed in `expected.periodText`.\n\t\t *\n\t\t * @param {string} value The ISO 8601 duration.\n\t\t * @return {string}\n\t\t */\n\t\tperiodLabel(value) {\n\t\t\tconst parsed = parseDuration(value)\n\t\t\tconst words = parsed\n\t\t\t\t? {\n\t\t\t\t\t\tyears: () => n('nextcloud-vue', '%n year', '%n years', parsed.amount),\n\t\t\t\t\t\tmonths: () => n('nextcloud-vue', '%n month', '%n months', parsed.amount),\n\t\t\t\t\t\tweeks: () => n('nextcloud-vue', '%n week', '%n weeks', parsed.amount),\n\t\t\t\t\t\tdays: () => n('nextcloud-vue', '%n day', '%n days', parsed.amount),\n\t\t\t\t\t}[parsed.unit]\n\t\t\t\t: null\n\t\t\tconst period = words ? words() : value\n\t\t\tconst template = this.content.expected?.periodText\n\t\t\treturn template ? this.text(template).replace('{period}', period) : period\n\t\t},\n\n\t\t/**\n\t\t * Read the record fresh from OpenRegister; a failure is an error, never an empty block.\n\t\t *\n\t\t * @spec openspec/changes/retention-widget/specs/retention-widget/spec.md#requirement-a-record-shows-its-stored-retention\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tif (!this.registerRef || !this.schemaRef || !this.id) {\n\t\t\t\t\tthrow new Error(t('nextcloud-vue', 'This widget has no record to read.'))\n\t\t\t\t}\n\t\t\t\tconst { data } = await axios.get(generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(this.registerRef)}/${encodeURIComponent(this.schemaRef)}/${encodeURIComponent(this.id)}`))\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : null\n\t\t\t\tawait this.loadExpected()\n\t\t\t} catch (failure) {\n\t\t\t\tconst body = failure && failure.response && failure.response.data\n\t\t\t\tthis.error = String((body && (body.message || body.error)) || (failure && failure.message) || failure)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the candidate rules `content.expected` names, for a record that\n\t\t * is not nominated yet. A failure leaves the plain pending facts.\n\t\t *\n\t\t * @spec openspec/changes/retention-expected-outcome/specs/retention-widget/spec.md#requirement-an-open-record-shows-the-outcome-its-type-expects\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadExpected() {\n\t\t\tconst source = this.content.expected && this.content.expected.source\n\t\t\tthis.expectedRows = null\n\t\t\tif (!source || !source.register || !source.schema || this.nomination) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst filter = resolveFilterTokens(source.filter || {}, { objectId: this.id, object: this.record })\n\t\t\tif (hasUnresolvedTokens(filter)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.get(generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(source.register)}/${encodeURIComponent(source.schema)}`), { params: { ...filter, _limit: 100 } })\n\t\t\t\tthis.expectedRows = Array.isArray(data?.results) ? data.results : []\n\t\t\t} catch {\n\t\t\t\tthis.expectedRows = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Ask OpenRegister to derive the nomination again with the reason the\n\t\t * dialog asked for, then read it back.\n\t\t *\n\t\t * @spec openspec/changes/retention-recompute-header/specs/retention-recompute-header/spec.md#requirement-recomputing-the-nomination-starts-in-the-card-header-and-asks-for-a-reason\n\t\t * @param {string} reason Why it is recomputed.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync recompute(reason) {\n\t\t\tconst why = String(reason ?? '').trim()\n\t\t\tif (this.busy || why === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\ttry {\n\t\t\t\tawait axios.post(generateUrl(`/apps/openregister/api/archival/objects/${encodeURIComponent(this.id)}/nomination/recompute`), { reason: why })\n\t\t\t\tthis.recomputeOpen = false\n\t\t\t\tawait this.load()\n\t\t\t} catch (failure) {\n\t\t\t\tconst body = failure && failure.response && failure.response.data\n\t\t\t\tthis.error = String((body && (body.message || body.error)) || (failure && failure.message) || failure)\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-retention {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-retention__head {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-start;\n\tjustify-content: space-between;\n\tgap: 10px 16px;\n}\n\n.cn-retention__head-text {\n\tdisplay: flex;\n\tflex: 1 1 260px;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-retention__title {\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-retention__muted {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-retention__facts {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n\tgap: 12px 24px;\n\tmargin: 0;\n}\n\n/* The server draws every dt as a 130px right-aligned inline block and pads\n dt and dd 12px; a fact is a label over its value. */\n.cn-retention__fact dt,\n.cn-retention__fact dd {\n\tdisplay: block;\n\twidth: auto;\n\twhite-space: normal;\n\ttext-align: start;\n}\n\n.cn-retention__fact dt {\n\tmargin: 0;\n\tpadding: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-retention__fact dd {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-weight: 600;\n}\n\n.cn-retention__section {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-retention__rows {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-retention__row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-retention__row-text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-retention__row-title {\n\tfont-weight: 600;\n}\n\n</style>\n"],"names":["CnRetentionRecomputeDialog","CnStatusBadge","t","n","axios"],"mappings":"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"}
1
+ {"version":3,"file":"CnRetentionWidget.vue2.js","sources":["../../../../src/components/CnRetentionWidget/CnRetentionWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-retention\" data-testid=\"cn-retention\">\n\t\t<header class=\"cn-retention__head\">\n\t\t\t<div class=\"cn-retention__head-text\">\n\t\t\t\t<h3 class=\"cn-retention__title\">\n\t\t\t\t\t{{ text(content.title) || t('nextcloud-vue', 'Archiving') }}\n\t\t\t\t</h3>\n\t\t\t\t<p class=\"cn-retention__muted\">\n\t\t\t\t\t{{ text(content.subtitle) || t('nextcloud-vue', 'What happens to this record once it is closed') }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<!-- Recompute starts in the header (board DqZaakArchivering); the\n\t\t\t dialog asks for the reason OpenRegister records with it. -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"content.recompute !== false && !loading && !error\"\n\t\t\t\t:disabled=\"!mayRecompute || busy\"\n\t\t\t\t:title=\"mayRecompute ? undefined : t('nextcloud-vue', 'Recomputing needs the archivist role')\"\n\t\t\t\t:aria-description=\"mayRecompute ? undefined : t('nextcloud-vue', 'Recomputing needs the archivist role')\"\n\t\t\t\t:data-testid=\"mayRecompute ? 'cn-retention-recompute-open' : 'cn-retention-recompute-denied'\"\n\t\t\t\t@click=\"recomputeOpen = true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<Refresh :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ t('nextcloud-vue', 'Recompute nomination') }}\n\t\t\t</NcButton>\n\t\t</header>\n\t\t<CnRetentionRecomputeDialog\n\t\t\tv-if=\"recomputeOpen\"\n\t\t\t:user=\"currentUid\"\n\t\t\t:busy=\"busy\"\n\t\t\t@close=\"recomputeOpen = false\"\n\t\t\t@confirm=\"recompute\" />\n\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"24\" />\n\t\t<NcEmptyContent v-else-if=\"error\"\n\t\t\t:name=\"t('nextcloud-vue', 'The archival facts are unavailable')\"\n\t\t\t:description=\"error\"\n\t\t\tdata-testid=\"cn-retention-error\">\n\t\t\t<template #action>\n\t\t\t\t<NcButton data-testid=\"cn-retention-retry\" @click=\"load\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Try again') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\n\t\t<template v-else>\n\t\t\t<p v-if=\"archived\" class=\"cn-retention__archived\" data-testid=\"cn-retention-archived\">\n\t\t\t\t{{ t('nextcloud-vue', 'Archived on {at} by {by}. {reason}', { at: String(archived.at ?? ''), by: String(archived.by ?? ''), reason: String(archived.reason ?? '') }) }}\n\t\t\t</p>\n\t\t\t<NcNoteCard v-if=\"disagrees\" type=\"warning\" data-testid=\"cn-retention-disagreement\">\n\t\t\t\t{{ t('nextcloud-vue', 'This record and OpenRegister do not agree on whether it is archived.') }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<NcNoteCard v-if=\"nomination && nomination.status === 'unnominatable'\" type=\"warning\" data-testid=\"cn-retention-unnominatable\">\n\t\t\t\t{{ t('nextcloud-vue', 'Nothing could decide what happens to this record.') }}\n\t\t\t\t{{ String(nomination.unnominatableReason ?? '') }}\n\t\t\t</NcNoteCard>\n\t\t\t<div v-else-if=\"!nomination\" data-testid=\"cn-retention-pending\">\n\t\t\t\t<dl class=\"cn-retention__facts\">\n\t\t\t\t\t<div v-for=\"fact in pendingFacts\" :key=\"fact.key\" class=\"cn-retention__fact\">\n\t\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t\t<dd>{{ fact.value }}</dd>\n\t\t\t\t\t</div>\n\t\t\t\t</dl>\n\t\t\t\t<NcNoteCard type=\"info\">\n\t\t\t\t\t{{ text(content.pendingNote) || t('nextcloud-vue', 'This record has not been closed yet. Its archival future is recorded when it closes.') }}\n\t\t\t\t</NcNoteCard>\n\t\t\t</div>\n\t\t\t<dl v-else class=\"cn-retention__facts\" data-testid=\"cn-retention-facts\">\n\t\t\t\t<div v-for=\"fact in facts\" :key=\"fact.key\" class=\"cn-retention__fact\">\n\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t<dd :data-testid=\"`cn-retention-${fact.key}`\">\n\t\t\t\t\t\t{{ fact.value }}\n\t\t\t\t\t</dd>\n\t\t\t\t</div>\n\t\t\t</dl>\n\n\t\t\t<section v-if=\"content.legalHold\" class=\"cn-retention__section\" data-testid=\"cn-retention-hold\">\n\t\t\t\t<component :is=\"innerHeadingTag\" class=\"cn-inner-heading\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Kept for a procedure') }}\n\t\t\t\t</component>\n\t\t\t\t<ul class=\"cn-retention__rows\">\n\t\t\t\t\t<li v-for=\"hold in holds\" :key=\"hold.id\" class=\"cn-retention__row\">\n\t\t\t\t\t\t<span class=\"cn-retention__mark cn-retention__mark--hold\" aria-hidden=\"true\">LH</span>\n\t\t\t\t\t\t<span class=\"cn-retention__row-text\">\n\t\t\t\t\t\t\t<span class=\"cn-retention__row-title\">{{ hold.reason || t('nextcloud-vue', 'Legal hold') }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-retention__muted\">{{ t('nextcloud-vue', 'Placed on {date} by {by}', { date: hold.placedDate, by: hold.placedBy }) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<CnStatusBadge :label=\"t('nextcloud-vue', 'Active')\" variant=\"warning\" />\n\t\t\t\t\t</li>\n\t\t\t\t\t<li v-if=\"holds.length === 0\" class=\"cn-retention__row\">\n\t\t\t\t\t\t<span class=\"cn-retention__mark cn-retention__mark--hold\" aria-hidden=\"true\">LH</span>\n\t\t\t\t\t\t<span class=\"cn-retention__row-text\">\n\t\t\t\t\t\t\t<span class=\"cn-retention__row-title\">{{ t('nextcloud-vue', 'No legal hold') }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-retention__muted\">{{ t('nextcloud-vue', 'If an objection or appeal runs, destruction is suspended') }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<CnStatusBadge :label=\"t('nextcloud-vue', 'None')\" />\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\n\t\t\t<section v-if=\"content.transfer\" class=\"cn-retention__section\" data-testid=\"cn-retention-transfer\">\n\t\t\t\t<component :is=\"innerHeadingTag\" class=\"cn-inner-heading\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Transfer to the e-Depot') }}\n\t\t\t\t</component>\n\t\t\t\t<ul class=\"cn-retention__rows\">\n\t\t\t\t\t<li class=\"cn-retention__row\">\n\t\t\t\t\t\t<span class=\"cn-retention__mark\" aria-hidden=\"true\">ED</span>\n\t\t\t\t\t\t<span class=\"cn-retention__row-text\">\n\t\t\t\t\t\t\t<span class=\"cn-retention__row-title\">{{ transfers ? t('nextcloud-vue', 'Goes to the e-Depot') : t('nextcloud-vue', 'Not applicable') }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-retention__muted\">{{ transfers ? t('nextcloud-vue', 'After the retention period the record is transferred') : t('nextcloud-vue', 'Only records appraised to keep go to the e-Depot') }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<CnStatusBadge :label=\"transfers ? t('nextcloud-vue', 'Transfer') : t('nextcloud-vue', 'No transfer')\" :variant=\"transfers ? 'info' : 'default'\" />\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\n\t\t\t<div v-if=\"outcome\" class=\"cn-retention__outcome\" data-testid=\"cn-retention-outcome\">\n\t\t\t\t<component :is=\"innerHeadingTag\" class=\"cn-inner-heading\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Outcome') }}\n\t\t\t\t</component>\n\t\t\t\t<p>{{ t('nextcloud-vue', 'Handed over as {kind} on {at} by {by}.', { kind: String(outcome.kind ?? ''), at: String(outcome.at ?? ''), by: String(outcome.by ?? '') }) }}</p>\n\t\t\t\t<p v-if=\"outcome.transferListUuid\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Transfer list') }}: {{ outcome.transferListUuid }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport CnRetentionRecomputeDialog from './CnRetentionRecomputeDialog.vue'\nimport innerHeading from '../../mixins/innerHeading.js'\nimport { parseDuration } from '../../utils/isoDuration.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { hasUnresolvedTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\n\n/**\n * CnRetentionWidget — the `retention` detail widget: what happens to a\n * record when its business use ends, as OpenRegister decided it. Every value\n * is read off the record's `@self._retention` (appraisal, disposal date,\n * retention period, selection list row, the rule and when it was written)\n * and `@self.archived`; the widget derives nothing, so it can never disagree\n * with the stored decision. A failed read is an error with a retry, never an\n * empty block. A record nothing could nominate is drawn apart from one that\n * is not closed yet. An archivist (or an admin) may ask OpenRegister to\n * recompute the nomination, with a reason. Any app on OpenRegister uses it;\n * dossiq's case Archiving tab is the first.\n *\n * `content`:\n * - `title`, `subtitle`: texts, through the host translate.\n * - `statusField`, `archivedValues`: a record field and the values that mean\n * archived (`archiveStatus`, `[\"archived\", ...]`); when set, a mismatch with\n * `@self.archived` is said out loud.\n * - `archivistGroups`: groups that may recompute (default `[\"archivaris\"]`;\n * admins always may); `recompute: false` hides the control.\n * - `expected`: before the record closes, the outcome its type expects.\n * `source: { register, schema, filter }` lists the candidate rules (a case\n * type's result types, `filter` tokens such as `@object.caseType`\n * resolved against the record); `fields: { appraisal, period,\n * selectionListRow }` names their fields; `appraisalLabels` names the\n * appraisal values; `periodText` writes the period (`{period} after the\n * decision`); `decidedBy` says who decides. When the candidates agree the\n * facts show that outcome, otherwise \"Depends on the result\". A failed\n * read keeps the plain facts.\n * - `pendingNote`: the note under the facts of a record not closed yet.\n * - `legalHold: true`: a section with the record's active legal holds\n * (`@self._retention.legalHold.holds`), or that none applies.\n * - `transfer: { keepValues }`: a section saying whether the record goes to\n * the e-Depot, from the stored or expected appraisal.\n *\n * The record is read fresh from OpenRegister by `register`, `schema` and\n * `objectId` (props, else the bound record's `@self`).\n */\nexport default {\n\tname: 'CnRetentionWidget',\n\n\tcomponents: { CnRetentionRecomputeDialog, CnStatusBadge, NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard, Refresh },\n\n\tmixins: [innerHeading],\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The bound record, on a detail page.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The record's register (else the bound record's `@self.register`). */\n\t\tregister: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record's schema (else the bound record's `@self.schema`); a schema object gives its slug.\n\t\t *\n\t\t * @type {string|number|object}\n\t\t */\n\t\tschema: {\n\t\t\ttype: [String, Number, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's id (else the bound record's). */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: true,\n\t\t\terror: '',\n\t\t\trecord: null,\n\t\t\t/** Whether the recompute dialog is open. */\n\t\t\trecomputeOpen: false,\n\t\t\tbusy: false,\n\t\t\t/** The candidate rules `content.expected` reads, null until read or when unreadable. */\n\t\t\texpectedRows: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The bound record's `@self`. */\n\t\tboundSelf() {\n\t\t\treturn (this.objectData && this.objectData['@self']) || {}\n\t\t},\n\n\t\t/** @return {string} The record id. */\n\t\tid() {\n\t\t\treturn String(this.objectId || (this.objectData && this.objectData.id) || this.boundSelf.id || '')\n\t\t},\n\n\t\t/** @return {string} The register. */\n\t\tregisterRef() {\n\t\t\treturn String(this.register || this.boundSelf.register || '')\n\t\t},\n\n\t\t/** @return {string} The schema. */\n\t\tschemaRef() {\n\t\t\tconst s = this.schema || this.boundSelf.schema || ''\n\t\t\treturn String(typeof s === 'object' ? (s.slug || s.id || '') : s)\n\t\t},\n\n\t\t/** @return {object} The record's `@self`. */\n\t\tself() {\n\t\t\treturn (this.record && this.record['@self']) || {}\n\t\t},\n\n\t\t/** @return {object|null} OpenRegister's stored retention decision. */\n\t\tretention() {\n\t\t\treturn this.self._retention || null\n\t\t},\n\n\t\t/** @return {object|null} The nomination. */\n\t\tnomination() {\n\t\t\treturn (this.retention && this.retention.nomination) || null\n\t\t},\n\n\t\t/** @return {object|null} The hand-over outcome. */\n\t\toutcome() {\n\t\t\treturn (this.retention && this.retention.outcome) || null\n\t\t},\n\n\t\t/** @return {object|null} OpenRegister's archived marker. */\n\t\tarchived() {\n\t\t\treturn this.self.archived || null\n\t\t},\n\n\t\t/**\n\t\t * Whether the record's own field and the platform marker disagree.\n\t\t *\n\t\t * @spec openspec/changes/retention-widget/specs/retention-widget/spec.md#requirement-a-record-shows-its-stored-retention\n\t\t * @return {boolean}\n\t\t */\n\t\tdisagrees() {\n\t\t\tconst field = this.content.statusField\n\t\t\tif (!field || !this.record) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst values = Array.isArray(this.content.archivedValues) ? this.content.archivedValues.map(String) : ['archived']\n\t\t\tconst saysArchived = values.includes(String(readPath(this.record, field) ?? ''))\n\t\t\treturn saysArchived !== Boolean(this.archived)\n\t\t},\n\n\t\t/**\n\t\t * The stored facts that have a value, in reading order.\n\t\t *\n\t\t * @spec openspec/changes/retention-widget/specs/retention-widget/spec.md#requirement-a-record-shows-its-stored-retention\n\t\t * @return {Array<{key: string, label: string, value: string}>}\n\t\t */\n\t\tfacts() {\n\t\t\tconst r = this.retention || {}\n\t\t\tconst n = this.nomination || {}\n\t\t\treturn [\n\t\t\t\t{ key: 'appraisal', label: t('nextcloud-vue', 'Appraisal'), value: r.appraisal },\n\t\t\t\t{ key: 'disposal-date', label: t('nextcloud-vue', 'Disposal date'), value: r.disposalDate },\n\t\t\t\t{ key: 'retention-period', label: t('nextcloud-vue', 'Retention period'), value: r.retentionPeriod },\n\t\t\t\t{ key: 'selection-list-row', label: t('nextcloud-vue', 'Selection list row'), value: r.selectionListRow },\n\t\t\t\t{ key: 'rule', label: t('nextcloud-vue', 'Decided by'), value: n.rule },\n\t\t\t\t{ key: 'decided-at', label: t('nextcloud-vue', 'Written on'), value: n.at },\n\t\t\t].filter((fact) => fact.value !== undefined && fact.value !== null && fact.value !== '').map((fact) => ({ ...fact, value: String(fact.value) }))\n\t\t},\n\n\t\t/**\n\t\t * The outcome the record's type expects before it closes: the agreed\n\t\t * appraisal, period and selection list row of the candidate rules, or\n\t\t * `mixed` when they disagree; null when nothing was read.\n\t\t *\n\t\t * @spec openspec/changes/retention-expected-outcome/specs/retention-widget/spec.md#requirement-an-open-record-shows-the-outcome-its-type-expects\n\t\t * @return {{appraisal: string, period: string, selectionListRow: string, mixed: boolean}|null}\n\t\t */\n\t\texpectedOutcome() {\n\t\t\tconst rows = this.expectedRows\n\t\t\tif (!Array.isArray(rows) || rows.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst fields = { appraisal: 'appraisal', period: 'period', selectionListRow: 'selectionListRow', ...(this.content.expected?.fields || {}) }\n\t\t\tconst pick = (row, key) => String(readPath(row, fields[key]) ?? '')\n\t\t\tconst outcomes = rows.map((row) => ({ appraisal: pick(row, 'appraisal'), period: pick(row, 'period'), selectionListRow: pick(row, 'selectionListRow') }))\n\t\t\tconst first = outcomes[0]\n\t\t\tconst agree = outcomes.every((o) => o.appraisal === first.appraisal && o.period === first.period)\n\t\t\tif (first.appraisal === '' && first.period === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn agree\n\t\t\t\t? { ...first, selectionListRow: outcomes.every((o) => o.selectionListRow === first.selectionListRow) ? first.selectionListRow : '', mixed: false }\n\t\t\t\t: { appraisal: '', period: '', selectionListRow: '', mixed: true }\n\t\t},\n\n\t\t/**\n\t\t * The facts of a record not closed yet: the expected outcome where the\n\t\t * type gives one, \"decided when it closes\" otherwise.\n\t\t *\n\t\t * @spec openspec/changes/retention-expected-outcome/specs/retention-widget/spec.md#requirement-an-open-record-shows-the-outcome-its-type-expects\n\t\t * @return {Array<{key: string, label: string, value: string}>}\n\t\t */\n\t\tpendingFacts() {\n\t\t\tconst atClosure = t('nextcloud-vue', 'Decided when it closes')\n\t\t\tconst expected = this.expectedOutcome\n\t\t\tif (!expected) {\n\t\t\t\treturn [\n\t\t\t\t\t{ key: 'appraisal', label: t('nextcloud-vue', 'Appraisal'), value: atClosure },\n\t\t\t\t\t{ key: 'retention-period', label: t('nextcloud-vue', 'Retention period'), value: atClosure },\n\t\t\t\t\t{ key: 'disposal-date', label: t('nextcloud-vue', 'Disposal date'), value: atClosure },\n\t\t\t\t\t{ key: 'decided-at', label: t('nextcloud-vue', 'Written on'), value: t('nextcloud-vue', 'Not yet') },\n\t\t\t\t]\n\t\t\t}\n\t\t\tconst depends = t('nextcloud-vue', 'Depends on the result')\n\t\t\tconst config = this.content.expected || {}\n\t\t\tconst facts = [\n\t\t\t\t{ key: 'appraisal', label: t('nextcloud-vue', 'Appraisal'), value: expected.mixed ? depends : this.appraisalLabel(expected.appraisal) },\n\t\t\t\t{ key: 'retention-period', label: t('nextcloud-vue', 'Retention period'), value: expected.mixed ? depends : this.periodLabel(expected.period) },\n\t\t\t]\n\t\t\tif (expected.selectionListRow) {\n\t\t\t\tfacts.push({ key: 'selection-list-row', label: t('nextcloud-vue', 'Selection list row'), value: expected.selectionListRow })\n\t\t\t}\n\t\t\tfacts.push({ key: 'disposal-date', label: t('nextcloud-vue', 'Disposal date'), value: atClosure })\n\t\t\tif (config.decidedBy) {\n\t\t\t\tfacts.push({ key: 'rule', label: t('nextcloud-vue', 'Decided by'), value: this.text(config.decidedBy) })\n\t\t\t}\n\t\t\tfacts.push({ key: 'decided-at', label: t('nextcloud-vue', 'Written on'), value: t('nextcloud-vue', 'Not yet') })\n\t\t\treturn facts.filter((fact) => fact.value !== '')\n\t\t},\n\n\t\t/** @return {Array<{id: string, reason: string, placedBy: string, placedDate: string}>} The active legal holds. */\n\t\tholds() {\n\t\t\tconst hold = (this.retention && this.retention.legalHold) || {}\n\t\t\tconst list = Array.isArray(hold.holds) ? hold.holds : []\n\t\t\treturn list.map((h, index) => ({ id: String(h.id ?? index), reason: String(h.reason ?? ''), placedBy: String(h.placedBy ?? ''), placedDate: String(h.placedDate ?? '') }))\n\t\t},\n\n\t\t/**\n\t\t * Whether the record goes to the e-Depot: its stored appraisal, else\n\t\t * the expected one, is one of `transfer.keepValues`.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\ttransfers() {\n\t\t\tconst keep = Array.isArray(this.content.transfer?.keepValues) ? this.content.transfer.keepValues.map(String) : ['bewaren', 'blijvend_bewaren', 'retain', 'keep']\n\t\t\tconst stored = this.retention && this.retention.appraisal\n\t\t\tconst appraisal = stored || (this.expectedOutcome && !this.expectedOutcome.mixed ? this.expectedOutcome.appraisal : '')\n\t\t\treturn keep.includes(String(appraisal || ''))\n\t\t},\n\n\t\t/** @return {string} The signed-in user's id. */\n\t\tcurrentUid() {\n\t\t\tconst user = getCurrentUser()\n\t\t\treturn String((user && user.uid) || '')\n\t\t},\n\n\t\t/**\n\t\t * Whether this user may recompute: an admin or an archivist group member.\n\t\t * Shown disabled otherwise, so the user learns which role it needs.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tmayRecompute() {\n\t\t\tconst user = getCurrentUser()\n\t\t\tif (user && user.isAdmin === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst groups = Array.isArray(user && user.groups) ? user.groups : []\n\t\t\tconst allowed = Array.isArray(this.content.archivistGroups) ? this.content.archivistGroups : ['archivaris']\n\t\t\treturn allowed.some((g) => groups.includes(g))\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * An appraisal value in words, through `expected.appraisalLabels`.\n\t\t *\n\t\t * @param {string} value The stored value.\n\t\t * @return {string}\n\t\t */\n\t\tappraisalLabel(value) {\n\t\t\tconst labels = this.content.expected?.appraisalLabels || {}\n\t\t\treturn labels[value] ? this.text(labels[value]) : value\n\t\t},\n\n\t\t/**\n\t\t * An ISO period in words (\"5 years\"), placed in `expected.periodText`.\n\t\t *\n\t\t * @param {string} value The ISO 8601 duration.\n\t\t * @return {string}\n\t\t */\n\t\tperiodLabel(value) {\n\t\t\tconst parsed = parseDuration(value)\n\t\t\tconst words = parsed\n\t\t\t\t? {\n\t\t\t\t\t\tyears: () => n('nextcloud-vue', '%n year', '%n years', parsed.amount),\n\t\t\t\t\t\tmonths: () => n('nextcloud-vue', '%n month', '%n months', parsed.amount),\n\t\t\t\t\t\tweeks: () => n('nextcloud-vue', '%n week', '%n weeks', parsed.amount),\n\t\t\t\t\t\tdays: () => n('nextcloud-vue', '%n day', '%n days', parsed.amount),\n\t\t\t\t\t}[parsed.unit]\n\t\t\t\t: null\n\t\t\tconst period = words ? words() : value\n\t\t\tconst template = this.content.expected?.periodText\n\t\t\treturn template ? this.text(template).replace('{period}', period) : period\n\t\t},\n\n\t\t/**\n\t\t * Read the record fresh from OpenRegister; a failure is an error, never an empty block.\n\t\t *\n\t\t * @spec openspec/changes/retention-widget/specs/retention-widget/spec.md#requirement-a-record-shows-its-stored-retention\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tif (!this.registerRef || !this.schemaRef || !this.id) {\n\t\t\t\t\tthrow new Error(t('nextcloud-vue', 'This widget has no record to read.'))\n\t\t\t\t}\n\t\t\t\tconst { data } = await axios.get(generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(this.registerRef)}/${encodeURIComponent(this.schemaRef)}/${encodeURIComponent(this.id)}`))\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : null\n\t\t\t\tawait this.loadExpected()\n\t\t\t} catch (failure) {\n\t\t\t\tconst body = failure && failure.response && failure.response.data\n\t\t\t\tthis.error = String((body && (body.message || body.error)) || (failure && failure.message) || failure)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Read the candidate rules `content.expected` names, for a record that\n\t\t * is not nominated yet. A failure leaves the plain pending facts.\n\t\t *\n\t\t * @spec openspec/changes/retention-expected-outcome/specs/retention-widget/spec.md#requirement-an-open-record-shows-the-outcome-its-type-expects\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadExpected() {\n\t\t\tconst source = this.content.expected && this.content.expected.source\n\t\t\tthis.expectedRows = null\n\t\t\tif (!source || !source.register || !source.schema || this.nomination) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst filter = resolveFilterTokens(source.filter || {}, { objectId: this.id, object: this.record })\n\t\t\tif (hasUnresolvedTokens(filter)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.get(generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(source.register)}/${encodeURIComponent(source.schema)}`), { params: { ...filter, _limit: 100 } })\n\t\t\t\tthis.expectedRows = Array.isArray(data?.results) ? data.results : []\n\t\t\t} catch {\n\t\t\t\tthis.expectedRows = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Ask OpenRegister to derive the nomination again with the reason the\n\t\t * dialog asked for, then read it back.\n\t\t *\n\t\t * @spec openspec/changes/retention-recompute-header/specs/retention-recompute-header/spec.md#requirement-recomputing-the-nomination-starts-in-the-card-header-and-asks-for-a-reason\n\t\t * @param {string} reason Why it is recomputed.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync recompute(reason) {\n\t\t\tconst why = String(reason ?? '').trim()\n\t\t\tif (this.busy || why === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\ttry {\n\t\t\t\tawait axios.post(generateUrl(`/apps/openregister/api/archival/objects/${encodeURIComponent(this.id)}/nomination/recompute`), { reason: why })\n\t\t\t\tthis.recomputeOpen = false\n\t\t\t\tawait this.load()\n\t\t\t} catch (failure) {\n\t\t\t\tconst body = failure && failure.response && failure.response.data\n\t\t\t\tthis.error = String((body && (body.message || body.error)) || (failure && failure.message) || failure)\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-retention {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-retention__head {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-start;\n\tjustify-content: space-between;\n\tgap: 10px 16px;\n}\n\n.cn-retention__head-text {\n\tdisplay: flex;\n\tflex: 1 1 260px;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-retention__title {\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-retention__muted {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-retention__facts {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n\tgap: 12px 24px;\n\tmargin: 0;\n}\n\n/* The server draws every dt as a 130px right-aligned inline block and pads\n dt and dd 12px; a fact is a label over its value. */\n.cn-retention__fact dt,\n.cn-retention__fact dd {\n\tdisplay: block;\n\twidth: auto;\n\twhite-space: normal;\n\ttext-align: start;\n}\n\n.cn-retention__fact dt {\n\tmargin: 0;\n\tpadding: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-retention__fact dd {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-weight: 600;\n}\n\n.cn-retention__section {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-retention__rows {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-retention__row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tpadding: 12px 0;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-retention__row-text {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n/* A round mark before a hold or transfer row: LH (legal hold) on the error\n tint, ED (e-Depot) on the chip ground (DqZaakArchivering). */\n.cn-retention__mark {\n\tdisplay: inline-flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 16px;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-retention__mark--hold {\n\tbackground: var(--color-error-light, #fcedec);\n\tcolor: var(--color-error-text, #a30000);\n}\n\n.cn-retention__row-title {\n\tfont-weight: 600;\n}\n\n</style>\n"],"names":["CnRetentionRecomputeDialog","CnStatusBadge","t","n","axios"],"mappings":"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"}
@@ -199,6 +199,10 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
199
199
  key: hold.id,
200
200
  class: "cn-retention__row"
201
201
  }, [
202
+ _cache[2] || (_cache[2] = createElementVNode("span", {
203
+ class: "cn-retention__mark cn-retention__mark--hold",
204
+ "aria-hidden": "true"
205
+ }, "LH", -1 /* CACHED */)),
202
206
  createElementVNode("span", _hoisted_13, [
203
207
  createElementVNode("span", _hoisted_14, toDisplayString(hold.reason || $options.t('nextcloud-vue', 'Legal hold')), 1 /* TEXT */),
204
208
  createElementVNode("span", _hoisted_15, toDisplayString($options.t('nextcloud-vue', 'Placed on {date} by {by}', { date: hold.placedDate, by: hold.placedBy })), 1 /* TEXT */)
@@ -211,6 +215,10 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
211
215
  }), 128 /* KEYED_FRAGMENT */)),
212
216
  ($options.holds.length === 0)
213
217
  ? (openBlock(), createElementBlock("li", _hoisted_16, [
218
+ _cache[3] || (_cache[3] = createElementVNode("span", {
219
+ class: "cn-retention__mark cn-retention__mark--hold",
220
+ "aria-hidden": "true"
221
+ }, "LH", -1 /* CACHED */)),
214
222
  createElementVNode("span", _hoisted_17, [
215
223
  createElementVNode("span", _hoisted_18, toDisplayString($options.t('nextcloud-vue', 'No legal hold')), 1 /* TEXT */),
216
224
  createElementVNode("span", _hoisted_19, toDisplayString($options.t('nextcloud-vue', 'If an objection or appeal runs, destruction is suspended')), 1 /* TEXT */)
@@ -233,6 +241,10 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
233
241
  })),
234
242
  createElementVNode("ul", _hoisted_21, [
235
243
  createElementVNode("li", _hoisted_22, [
244
+ _cache[4] || (_cache[4] = createElementVNode("span", {
245
+ class: "cn-retention__mark",
246
+ "aria-hidden": "true"
247
+ }, "ED", -1 /* CACHED */)),
236
248
  createElementVNode("span", _hoisted_23, [
237
249
  createElementVNode("span", _hoisted_24, toDisplayString($options.transfers ? $options.t('nextcloud-vue', 'Goes to the e-Depot') : $options.t('nextcloud-vue', 'Not applicable')), 1 /* TEXT */),
238
250
  createElementVNode("span", _hoisted_25, toDisplayString($options.transfers ? $options.t('nextcloud-vue', 'After the retention period the record is transferred') : $options.t('nextcloud-vue', 'Only records appraised to keep go to the e-Depot')), 1 /* TEXT */)