@conduction/nextcloud-vue 2.119.0 → 2.120.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 (126) hide show
  1. package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue.js +9 -0
  2. package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue.js.map +1 -0
  3. package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue2.js +226 -0
  4. package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue2.js.map +1 -0
  5. package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue3.js +211 -0
  6. package/dist/esm/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue3.js.map +1 -0
  7. package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue.js +9 -0
  8. package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue.js.map +1 -0
  9. package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue2.js +64 -0
  10. package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue2.js.map +1 -0
  11. package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue3.js +89 -0
  12. package/dist/esm/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue3.js.map +1 -0
  13. package/dist/esm/components/CnIcon/semanticIcons.js +2 -2
  14. package/dist/esm/components/CnIcon/semanticIcons.js.map +1 -1
  15. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue.js +9 -0
  16. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue.js.map +1 -0
  17. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue2.js +257 -0
  18. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue2.js.map +1 -0
  19. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue3.js +266 -0
  20. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue3.js.map +1 -0
  21. package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue.js +1 -1
  22. package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue2.js +14 -7
  23. package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue2.js.map +1 -1
  24. package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue3.js.map +1 -1
  25. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue.js +9 -0
  26. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue.js.map +1 -0
  27. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue2.js +278 -0
  28. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue2.js.map +1 -0
  29. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue3.js +128 -0
  30. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue3.js.map +1 -0
  31. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue.js +10 -0
  32. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue.js.map +1 -0
  33. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue2.js +944 -0
  34. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue2.js.map +1 -0
  35. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue3.js +276 -0
  36. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue3.js.map +1 -0
  37. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue.js +9 -0
  38. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue.js.map +1 -0
  39. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue2.js +354 -0
  40. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue2.js.map +1 -0
  41. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue3.js +392 -0
  42. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue3.js.map +1 -0
  43. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue.js +9 -0
  44. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue.js.map +1 -0
  45. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue2.js +180 -0
  46. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue2.js.map +1 -0
  47. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue3.js +208 -0
  48. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue3.js.map +1 -0
  49. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue.js +9 -0
  50. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue.js.map +1 -0
  51. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue2.js +244 -0
  52. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue2.js.map +1 -0
  53. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue3.js +76 -0
  54. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue3.js.map +1 -0
  55. package/dist/esm/components/CnStateMachineEditor/stateMachineFields.js +290 -0
  56. package/dist/esm/components/CnStateMachineEditor/stateMachineFields.js.map +1 -0
  57. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +9 -0
  58. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js.map +1 -0
  59. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js +448 -0
  60. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -0
  61. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +303 -0
  62. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -0
  63. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +1 -1
  64. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +19 -2
  65. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -1
  66. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js +73 -62
  67. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -1
  68. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +6 -0
  69. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
  70. package/dist/esm/index.js +5 -0
  71. package/dist/esm/index.js.map +1 -1
  72. package/dist/esm/l10n/en.json.js +166 -1
  73. package/dist/esm/l10n/en.json.js.map +1 -1
  74. package/dist/esm/l10n/nl.json.js +166 -1
  75. package/dist/esm/l10n/nl.json.js.map +1 -1
  76. package/dist/esm/library-style.js +1 -1
  77. package/dist/esm/nextcloud-vue.css +889 -101
  78. package/dist/esm/utils/aiFeatures.js +245 -0
  79. package/dist/esm/utils/aiFeatures.js.map +1 -0
  80. package/dist/esm/utils/aiSuggestionTracker.js +182 -0
  81. package/dist/esm/utils/aiSuggestionTracker.js.map +1 -0
  82. package/dist/esm/utils/libraryWidgetKeys.js +1 -0
  83. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  84. package/dist/esm/utils/objectPermissions.js +552 -0
  85. package/dist/esm/utils/objectPermissions.js.map +1 -0
  86. package/dist/esm/utils/objectTranslations.js +180 -0
  87. package/dist/esm/utils/objectTranslations.js.map +1 -0
  88. package/dist/esm/utils/stateMachineValidation.js +254 -0
  89. package/dist/esm/utils/stateMachineValidation.js.map +1 -0
  90. package/dist/esm/utils/widgetDispatch.js +3 -1
  91. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  92. package/dist/nextcloud-vue.cjs.js +20052 -13138
  93. package/dist/nextcloud-vue.cjs.js.map +2 -2
  94. package/dist/nextcloud-vue.css +889 -101
  95. package/l10n/en.json +166 -1
  96. package/l10n/nl.json +166 -1
  97. package/package.json +1 -1
  98. package/src/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue +416 -0
  99. package/src/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue +136 -0
  100. package/src/components/CnAiFeaturesWidget/__tests__/CnAiFeaturesWidget.spec.js +213 -0
  101. package/src/components/CnAiFeaturesWidget/index.js +14 -0
  102. package/src/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue +499 -0
  103. package/src/components/CnObjectPermissionsTab/__tests__/CnObjectPermissionsTab.spec.js +186 -0
  104. package/src/components/CnObjectPermissionsTab/index.js +13 -0
  105. package/src/components/CnObjectSidebar/CnObjectSidebar.vue +8 -1
  106. package/src/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue +424 -0
  107. package/src/components/CnObjectTranslationsWidget/__tests__/CnObjectTranslationsWidget.spec.js +189 -0
  108. package/src/components/CnObjectTranslationsWidget/index.js +13 -0
  109. package/src/components/CnStateMachineEditor/CnStateMachineEditor.vue +1332 -0
  110. package/src/components/CnStateMachineEditor/CnStateMachineFields.vue +791 -0
  111. package/src/components/CnStateMachineEditor/CnStateMachineNode.vue +442 -0
  112. package/src/components/CnStateMachineEditor/CnStateMachinePanel.vue +326 -0
  113. package/src/components/CnStateMachineEditor/index.js +8 -0
  114. package/src/components/CnStateMachineEditor/stateMachineFields.js +287 -0
  115. package/src/components/CnTimelineWidget/CnTimelineManage.vue +827 -0
  116. package/src/components/CnTimelineWidget/CnTimelineWidget.vue +29 -3
  117. package/src/components/CnWidgetGrid/builtInWidgets.js +6 -0
  118. package/src/components/index.js +4 -0
  119. package/src/index.js +5 -0
  120. package/src/utils/aiFeatures.js +241 -0
  121. package/src/utils/aiSuggestionTracker.js +178 -0
  122. package/src/utils/libraryWidgetKeys.js +1 -0
  123. package/src/utils/objectPermissions.js +548 -0
  124. package/src/utils/objectTranslations.js +176 -0
  125. package/src/utils/stateMachineValidation.js +250 -0
  126. package/src/utils/widgetDispatch.js +3 -1
@@ -1,4 +1,4 @@
1
- import { resolveComponent, openBlock, createElementBlock, toDisplayString, createCommentVNode, createVNode, createElementVNode, Fragment, createBlock, withCtx, createTextVNode, renderList, normalizeClass } from 'vue';
1
+ import { resolveComponent, openBlock, createBlock, createElementBlock, toDisplayString, createCommentVNode, createVNode, createElementVNode, Fragment, withCtx, createTextVNode, renderList, normalizeClass } from 'vue';
2
2
 
3
3
  const _hoisted_1 = ["aria-busy"];
4
4
  const _hoisted_2 = {
@@ -32,70 +32,81 @@ const _hoisted_11 = {
32
32
  };
33
33
 
34
34
  function render(_ctx, _cache, $props, $setup, $data, $options) {
35
+ const _component_CnTimelineManage = resolveComponent("CnTimelineManage");
35
36
  const _component_NcLoadingIcon = resolveComponent("NcLoadingIcon");
36
37
  const _component_NcNoteCard = resolveComponent("NcNoteCard");
37
38
 
38
- return (openBlock(), createElementBlock("section", {
39
- class: "cn-timeline-widget",
40
- "data-testid": "cn-timeline-widget",
41
- "aria-busy": $data.loading ? 'true' : 'false'
42
- }, [
43
- ($options.resolvedTitle)
44
- ? (openBlock(), createElementBlock("h3", _hoisted_2, toDisplayString($options.resolvedTitle), 1 /* TEXT */))
45
- : createCommentVNode("v-if", true),
46
- ($data.loading && $options.events.length === 0)
47
- ? (openBlock(), createElementBlock("div", _hoisted_3, [
48
- createVNode(_component_NcLoadingIcon, {
49
- size: 24,
50
- "aria-hidden": "true"
51
- }),
52
- createElementVNode("span", null, toDisplayString($options.loadingLabel), 1 /* TEXT */)
53
- ]))
54
- : (openBlock(), createElementBlock(Fragment, { key: 2 }, [
55
- ($data.failedSources.length > 0)
56
- ? (openBlock(), createBlock(_component_NcNoteCard, {
57
- key: 0,
58
- type: "warning",
59
- "data-testid": "cn-timeline-widget-error"
60
- }, {
61
- default: withCtx(() => [
62
- createTextVNode(toDisplayString($options.failedText), 1 /* TEXT */)
63
- ]),
64
- _: 1 /* STABLE */
65
- }))
66
- : createCommentVNode("v-if", true),
67
- ($options.events.length === 0)
68
- ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString($options.emptyLabel), 1 /* TEXT */))
69
- : (openBlock(), createElementBlock("ol", _hoisted_5, [
70
- (openBlock(true), createElementBlock(Fragment, null, renderList($options.events, (event) => {
71
- return (openBlock(), createElementBlock("li", {
72
- key: event.id,
73
- class: normalizeClass(["cn-timeline-widget__event", { 'cn-timeline-widget__event--upcoming': event.upcoming }]),
74
- "data-source": event.source,
75
- "data-testid": "cn-timeline-widget-event"
76
- }, [
77
- _cache[0] || (_cache[0] = createElementVNode("span", {
78
- class: "cn-timeline-widget__dot",
79
- "aria-hidden": "true"
80
- }, null, -1 /* CACHED */)),
81
- createElementVNode("div", _hoisted_7, [
82
- createElementVNode("time", {
83
- class: "cn-timeline-widget__when",
84
- datetime: event.at.toISOString()
85
- }, toDisplayString($options.formatMoment(event)), 9 /* TEXT, PROPS */, _hoisted_8),
86
- (event.upcoming)
87
- ? (openBlock(), createElementBlock("span", _hoisted_9, toDisplayString($options.upcomingLabel), 1 /* TEXT */))
88
- : createCommentVNode("v-if", true),
89
- createElementVNode("p", _hoisted_10, toDisplayString($options.translate(event.label)), 1 /* TEXT */),
90
- (event.detail)
91
- ? (openBlock(), createElementBlock("p", _hoisted_11, toDisplayString(event.detail), 1 /* TEXT */))
92
- : createCommentVNode("v-if", true)
93
- ])
94
- ], 10 /* CLASS, PROPS */, _hoisted_6))
95
- }), 128 /* KEYED_FRAGMENT */))
96
- ]))
97
- ], 64 /* STABLE_FRAGMENT */))
98
- ], 8 /* PROPS */, _hoisted_1))
39
+ return ($options.manage)
40
+ ? (openBlock(), createBlock(_component_CnTimelineManage, {
41
+ key: 0,
42
+ register: $options.resolvedRegister,
43
+ schema: $options.resolvedSchema,
44
+ objectId: $options.resolvedObjectId,
45
+ apiBase: $props.apiBase,
46
+ content: $props.content
47
+ }, null, 8 /* PROPS */, ["register", "schema", "objectId", "apiBase", "content"]))
48
+ : (openBlock(), createElementBlock("section", {
49
+ key: 1,
50
+ class: "cn-timeline-widget",
51
+ "data-testid": "cn-timeline-widget",
52
+ "aria-busy": $data.loading ? 'true' : 'false'
53
+ }, [
54
+ ($options.resolvedTitle)
55
+ ? (openBlock(), createElementBlock("h3", _hoisted_2, toDisplayString($options.resolvedTitle), 1 /* TEXT */))
56
+ : createCommentVNode("v-if", true),
57
+ ($data.loading && $options.events.length === 0)
58
+ ? (openBlock(), createElementBlock("div", _hoisted_3, [
59
+ createVNode(_component_NcLoadingIcon, {
60
+ size: 24,
61
+ "aria-hidden": "true"
62
+ }),
63
+ createElementVNode("span", null, toDisplayString($options.loadingLabel), 1 /* TEXT */)
64
+ ]))
65
+ : (openBlock(), createElementBlock(Fragment, { key: 2 }, [
66
+ ($data.failedSources.length > 0)
67
+ ? (openBlock(), createBlock(_component_NcNoteCard, {
68
+ key: 0,
69
+ type: "warning",
70
+ "data-testid": "cn-timeline-widget-error"
71
+ }, {
72
+ default: withCtx(() => [
73
+ createTextVNode(toDisplayString($options.failedText), 1 /* TEXT */)
74
+ ]),
75
+ _: 1 /* STABLE */
76
+ }))
77
+ : createCommentVNode("v-if", true),
78
+ ($options.events.length === 0)
79
+ ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString($options.emptyLabel), 1 /* TEXT */))
80
+ : (openBlock(), createElementBlock("ol", _hoisted_5, [
81
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.events, (event) => {
82
+ return (openBlock(), createElementBlock("li", {
83
+ key: event.id,
84
+ class: normalizeClass(["cn-timeline-widget__event", { 'cn-timeline-widget__event--upcoming': event.upcoming }]),
85
+ "data-source": event.source,
86
+ "data-testid": "cn-timeline-widget-event"
87
+ }, [
88
+ _cache[0] || (_cache[0] = createElementVNode("span", {
89
+ class: "cn-timeline-widget__dot",
90
+ "aria-hidden": "true"
91
+ }, null, -1 /* CACHED */)),
92
+ createElementVNode("div", _hoisted_7, [
93
+ createElementVNode("time", {
94
+ class: "cn-timeline-widget__when",
95
+ datetime: event.at.toISOString()
96
+ }, toDisplayString($options.formatMoment(event)), 9 /* TEXT, PROPS */, _hoisted_8),
97
+ (event.upcoming)
98
+ ? (openBlock(), createElementBlock("span", _hoisted_9, toDisplayString($options.upcomingLabel), 1 /* TEXT */))
99
+ : createCommentVNode("v-if", true),
100
+ createElementVNode("p", _hoisted_10, toDisplayString($options.translate(event.label)), 1 /* TEXT */),
101
+ (event.detail)
102
+ ? (openBlock(), createElementBlock("p", _hoisted_11, toDisplayString(event.detail), 1 /* TEXT */))
103
+ : createCommentVNode("v-if", true)
104
+ ])
105
+ ], 10 /* CLASS, PROPS */, _hoisted_6))
106
+ }), 128 /* KEYED_FRAGMENT */))
107
+ ]))
108
+ ], 64 /* STABLE_FRAGMENT */))
109
+ ], 8 /* PROPS */, _hoisted_1))
99
110
  }
100
111
 
101
112
  export { render };
@@ -1 +1 @@
1
- {"version":3,"file":"CnTimelineWidget.vue3.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineWidget.vue?vue&type=template&id=091aa98d&lang.js"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<section class=\"cn-timeline-widget\" data-testid=\"cn-timeline-widget\" :aria-busy=\"loading ? 'true' : 'false'\">\n\t\t<h3 v-if=\"resolvedTitle\" class=\"cn-timeline-widget__title\">\n\t\t\t{{ resolvedTitle }}\n\t\t</h3>\n\n\t\t<div v-if=\"loading && events.length === 0\" class=\"cn-timeline-widget__loading\">\n\t\t\t<NcLoadingIcon :size=\"24\" aria-hidden=\"true\" />\n\t\t\t<span>{{ loadingLabel }}</span>\n\t\t</div>\n\n\t\t<template v-else>\n\t\t\t<!-- A failed read is not an empty history: say which part is missing. -->\n\t\t\t<NcNoteCard v-if=\"failedSources.length > 0\" type=\"warning\" data-testid=\"cn-timeline-widget-error\">\n\t\t\t\t{{ failedText }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"events.length === 0\" class=\"cn-timeline-widget__empty\" data-testid=\"cn-timeline-widget-empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\n\t\t\t<ol v-else class=\"cn-timeline-widget__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"event in events\"\n\t\t\t\t\t:key=\"event.id\"\n\t\t\t\t\tclass=\"cn-timeline-widget__event\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-widget__event--upcoming': event.upcoming }\"\n\t\t\t\t\t:data-source=\"event.source\"\n\t\t\t\t\tdata-testid=\"cn-timeline-widget-event\">\n\t\t\t\t\t<span class=\"cn-timeline-widget__dot\" aria-hidden=\"true\" />\n\t\t\t\t\t<div class=\"cn-timeline-widget__body\">\n\t\t\t\t\t\t<time class=\"cn-timeline-widget__when\" :datetime=\"event.at.toISOString()\">\n\t\t\t\t\t\t\t{{ formatMoment(event) }}\n\t\t\t\t\t\t</time>\n\t\t\t\t\t\t<span v-if=\"event.upcoming\" class=\"cn-timeline-widget__badge\">\n\t\t\t\t\t\t\t{{ upcomingLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<p class=\"cn-timeline-widget__label\">\n\t\t\t\t\t\t\t{{ translate(event.label) }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"event.detail\" class=\"cn-timeline-widget__detail\">\n\t\t\t\t\t\t\t{{ event.detail }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</template>\n\t</section>\n</template>\n\n<script>\nimport { getLanguage, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { auditEvents, fieldEvents, listEvents, relatedEvents, sortEvents, timelineEntryEvents } from '../../utils/timelineEvents.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnTimelineWidget — an object's dated events in time order (`timeline`\n * widget type for detail pages).\n *\n * Generalises dossiq's case timeline. It merges up to four sources, all\n * optional, into one list:\n *\n * - `fields`: the object's own date properties, `[{ field, label }]`. A\n * dotted path reaches metadata, such as `@self.created`.\n * - `related`: related objects, `[{ register?, schema, field, dateField?,\n * label, titleField? }]`. Rows of `schema` whose `field` holds this object's\n * id become events at their `dateField` (default `@self.created`).\n * - `auditTrail: true`: the object's audit trail, one event per change.\n * - `timeline: true`: OpenRegister's timeline of notes, calls and messages.\n *\n * Oldest first by default (`order: 'desc'` flips it). A moment after now is\n * marked upcoming, in words as well as style.\n *\n * ```json\n * { \"type\": \"timeline\", \"content\": {\n * \"title\": \"Timeline\",\n * \"fields\": [\n * { \"field\": \"@self.created\", \"label\": \"Booking created\" },\n * { \"field\": \"depositClearedAt\", \"label\": \"Deposit cleared\" },\n * { \"field\": \"confirmationSentAt\", \"label\": \"Confirmation mail sent\" },\n * { \"field\": \"startsAt\", \"label\": \"Starts\" },\n * { \"field\": \"endsAt\", \"label\": \"Ends\" }\n * ] } }\n * ```\n *\n * The object comes from the detail page's context, like `audit-trail`:\n * explicit props win, then the injects, then `content`.\n *\n * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n */\nexport default {\n\tname: 'CnTimelineWidget',\n\n\tcomponents: {\n\t\tNcLoadingIcon,\n\t\tNcNoteCard,\n\t},\n\n\tinject: {\n\t\t/** Detail-page object context from CnDetailPage (a ref or a raw bag). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Detail object context holder from CnPageRenderer (`{ value: { objectData, ... } }`). */\n\t\tcnDetailObjectContext: { default: null },\n\t\t/** Consumer translation function; labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Register slug; object context spread as props by CnWidgetGrid. */\n\t\tregister: { type: String, default: '' },\n\t\t/**\n\t\t * Schema slug, or the schema object the detail context supplies.\n\t\t *\n\t\t * @type {string|object}\n\t\t */\n\t\tschema: { type: [String, Object], default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** The object itself, when the host already has it. */\n\t\tobject: { type: Object, default: null },\n\t\t/** Card title override. */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Stored widget content: `{ title, fields, related, auditTrail, timeline, order }`. */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: false,\n\t\t\trelatedRows: {},\n\t\t\tauditEntries: [],\n\t\t\ttimelineEntries: [],\n\t\t\tfailedSources: [],\n\t\t\tfetchedObject: null,\n\t\t\tloadSeq: 0,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tctx() {\n\t\t\tconst raw = this.cnObjectContext\n\t\t\tconst inj = raw && (raw.value !== undefined ? raw.value : raw)\n\t\t\tconst holder = this.cnDetailObjectContext && this.cnDetailObjectContext.value\n\t\t\treturn inj || holder || {}\n\t\t},\n\n\t\tresolvedObjectId() {\n\t\t\treturn this.objectId || this.ctx.objectId || this.content.objectId || ''\n\t\t},\n\n\t\tresolvedRegister() {\n\t\t\treturn this.register || this.ctx.register || this.content.register || ''\n\t\t},\n\n\t\tresolvedSchema() {\n\t\t\tconst s = this.schema || this.ctx.schema || this.content.schema || ''\n\t\t\treturn typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''\n\t\t},\n\n\t\t/**\n\t\t * The object: explicit prop, then the page context, then a fetch of\n\t\t * our own when only the id is known.\n\t\t *\n\t\t * @return {object|null}\n\t\t */\n\t\tresolvedObject() {\n\t\t\treturn this.object || this.ctx.object || this.ctx.objectData || this.fetchedObject || null\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\tconst raw = this.title || this.content.title || ''\n\t\t\treturn raw ? this.translate(raw) : ''\n\t\t},\n\n\t\tfieldsConfig() {\n\t\t\treturn Array.isArray(this.content.fields) ? this.content.fields : []\n\t\t},\n\n\t\trelatedConfig() {\n\t\t\treturn Array.isArray(this.content.related) ? this.content.related.filter((r) => r && r.schema && r.field) : []\n\t\t},\n\n\t\t/**\n\t\t * Every event from every source, in time order.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tevents() {\n\t\t\tconst now = new Date()\n\t\t\tconst all = [\n\t\t\t\t...fieldEvents(this.resolvedObject || {}, this.fieldsConfig, now),\n\t\t\t\t...listEvents(this.resolvedObject || {}, this.content.lists, now),\n\t\t\t\t...this.relatedConfig.flatMap((cfg, i) => relatedEvents(this.relatedRows[i] || [], cfg, now)),\n\t\t\t\t...auditEvents(this.auditEntries, this.describeAudit, now),\n\t\t\t\t...timelineEntryEvents(this.timelineEntries, t('nextcloud-vue', 'Note'), now),\n\t\t\t]\n\t\t\treturn sortEvents(all, this.content.order === 'desc' ? 'desc' : 'asc')\n\t\t},\n\n\t\t/**\n\t\t * A signature of what to fetch, so a change refetches once.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tloadKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\tid: this.resolvedObjectId,\n\t\t\t\tregister: this.resolvedRegister,\n\t\t\t\tschema: this.resolvedSchema,\n\t\t\t\trelated: this.relatedConfig,\n\t\t\t\taudit: this.content.auditTrail === true,\n\t\t\t\ttimeline: this.content.timeline === true,\n\t\t\t\tneedObject: this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData),\n\t\t\t})\n\t\t},\n\n\t\tfailedText() {\n\t\t\treturn t('nextcloud-vue', 'Part of the timeline could not load: {parts}.', {\n\t\t\t\tparts: this.failedSources.map((s) => this.sourceName(s)).join(', '),\n\t\t\t})\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing has happened yet.')\n\t\t},\n\n\t\tupcomingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Upcoming')\n\t\t},\n\t},\n\n\twatch: {\n\t\tloadKey: {\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\tmethods: {\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\tsourceName(source) {\n\t\t\tif (source === 'audit') {\n\t\t\t\treturn t('nextcloud-vue', 'changes')\n\t\t\t}\n\t\t\tif (source === 'timeline') {\n\t\t\t\treturn t('nextcloud-vue', 'notes and messages')\n\t\t\t}\n\t\t\tif (source === 'object') {\n\t\t\t\treturn t('nextcloud-vue', 'dates')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'related items')\n\t\t},\n\n\t\t/**\n\t\t * The label of an audit event, from its action and who did it.\n\t\t *\n\t\t * @param {string} action The audit action (create, update, delete).\n\t\t * @param {string} actor Who did it.\n\t\t * @return {string}\n\t\t */\n\t\tdescribeAudit(action, actor) {\n\t\t\tconst known = {\n\t\t\t\tcreate: t('nextcloud-vue', 'Created'),\n\t\t\t\tupdate: t('nextcloud-vue', 'Updated'),\n\t\t\t\tdelete: t('nextcloud-vue', 'Deleted'),\n\t\t\t}\n\t\t\tconst what = known[action] || action || t('nextcloud-vue', 'Changed')\n\t\t\treturn actor ? t('nextcloud-vue', '{action} by {actor}', { action: what, actor }) : what\n\t\t},\n\n\t\t/**\n\t\t * Show a moment in the reader's language: a date for a calendar day,\n\t\t * date and time otherwise.\n\t\t *\n\t\t * @param {object} event The event.\n\t\t * @return {string}\n\t\t */\n\t\tformatMoment(event) {\n\t\t\tconst locale = (typeof getLanguage === 'function' && getLanguage()) || undefined\n\t\t\tconst options = event.dateOnly\n\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale, options).format(event.at)\n\t\t\t} catch {\n\t\t\t\treturn event.at.toLocaleString(userLocale())\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch every configured source. Each one fails on its own, so one\n\t\t * unreachable source never hides the others.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n\t\t */\n\t\tasync load() {\n\t\t\tconst id = this.resolvedObjectId\n\t\t\tconst register = this.resolvedRegister\n\t\t\tconst schema = this.resolvedSchema\n\t\t\tconst seq = ++this.loadSeq\n\t\t\tif (!id || !register || !schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\timport('@nextcloud/router'),\n\t\t\t])\n\t\t\tconst base = `${this.apiBase}/objects/${register}/${schema}/${id}`\n\t\t\tconst failed = []\n\t\t\tconst jobs = []\n\n\t\t\tif (this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData)) {\n\t\t\t\tjobs.push(axios.get(generateUrl(base))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tthis.fetchedObject = (r && r.data) || null\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => failed.push('object')))\n\t\t\t}\n\n\t\t\tconst rows = {}\n\t\t\tthis.relatedConfig.forEach((cfg, i) => {\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${cfg.register || register}/${cfg.schema}`)\n\t\t\t\tjobs.push(axios.get(url, { params: { [cfg.field]: id, _limit: cfg.limit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\trows[i] = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\trows[i] = []\n\t\t\t\t\t\tif (!failed.includes('related')) {\n\t\t\t\t\t\t\tfailed.push('related')\n\t\t\t\t\t\t}\n\t\t\t\t\t}))\n\t\t\t})\n\n\t\t\tif (this.content.auditTrail === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/audit-trails`), { params: { limit: this.content.auditLimit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.auditEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.auditEntries = []\n\t\t\t\t\t\tfailed.push('audit')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (this.content.timeline === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/timeline`))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.timelineEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.timelineEntries = []\n\t\t\t\t\t\tfailed.push('timeline')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (jobs.length === 0) {\n\t\t\t\tthis.failedSources = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tawait Promise.all(jobs)\n\t\t\tif (seq !== this.loadSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.relatedRows = rows\n\t\t\tthis.failedSources = failed\n\t\t\tthis.loading = false\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-timeline-widget__title {\n\tmargin: 0;\n\tfont-size: var(--font-size-large, 1.1em);\n}\n\n.cn-timeline-widget__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__list {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-timeline-widget__event {\n\tposition: relative;\n\tdisplay: flex;\n\tgap: 12px;\n\tpadding-block-end: 12px;\n}\n\n/* The line between dots: drawn from each dot down to the next event. */\n.cn-timeline-widget__event:not(:last-child)::before {\n\tcontent: '';\n\tposition: absolute;\n\tinset-block: 14px 0;\n\tinset-inline-start: 5px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n}\n\n.cn-timeline-widget__dot {\n\tflex: 0 0 auto;\n\twidth: 12px;\n\theight: 12px;\n\tmargin-block-start: 4px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-primary-element);\n}\n\n/* Upcoming: a hollow dot, plus the word \"Upcoming\" beside the date. */\n.cn-timeline-widget__event--upcoming .cn-timeline-widget__dot {\n\tbox-sizing: border-box;\n\tborder: 2px solid var(--color-primary-element);\n\tbackground-color: var(--color-main-background);\n}\n\n.cn-timeline-widget__body {\n\tmin-width: 0;\n}\n\n.cn-timeline-widget__when {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__badge {\n\tmargin-inline-start: 8px;\n\tfont-size: var(--font-size-small, 13px);\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-widget__label {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-timeline-widget__detail {\n\tmargin: 0;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["_createElementBlock","_toDisplayString","_createVNode","_createBlock","_openBlock","_Fragment","_renderList","_normalizeClass","_createElementVNode"],"mappings":";;;;;AAMM,EAAA,KAAA,EAAA,2BAAA;;;;AAI2B,EAAA,KAAA,EAAA,6BAAA;;;;AAW3B,EAAA,KAAA,EAAA,2BAAA;AAAA,EAAA,aAAA,EAAA,0BAAA;;;;AAIQ,EAAA,KAAK,EAAE,0BAAM;;;AASjB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,0BAAe,GAAA;;;;AAInB,EAAA,KAAA,EAAA,2BAAA;;AAGH,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,2BAAA,GAAA;;;AAGA,EAAA,KAAA,EAAA,4BAAA;;;;;;;uBAvCNA;AAAO,IAAA,KAAK,EAAC,oBAAK;AAAA,IAAA,aAAA,EAAA,oBAAA;AAAA,IAAA,WAAA,EAAA,KAAA,CAAA,OAAA,GAAA,MAAA,GAAA,OAAA;;KACf,QAAA,CAAA,aAAA;sBAAJA,kBAEK,CAAA,IAAA,EAFL,UAEK,EAAAC,eAAA;;KAEM,KAAO,CAAA,OAAA,IAAK,QAAK,CAAA,MAAA,CAAC,MAAE,KAAA,CAAA;yCAGzB,iBAAA,EAAA;UAFLC,WAAI,CAAA,wBAAA,EAAA;AAAA,YAAA,IAAA,EAAA,EAAA;AAAA,YAAA,aAAA,EAAA,MAAA;;;;sBAIJF;AAEY,UAAA,CAAA,KAAA,CAAA,aAAA,CAAA,MAAA,GAAA,CAAA;4BAAZG,WAEa,CAAA,qBAAA,EAAA;;AAFD,gBAAA,IAAA,EAAA,SAAA;AAAA,gBAAA,aAAA,EAAA,0BAAA;;;;;;;;AAIT,UAAA,CAAA,QAAA,CAAA,MAAA,CAAA,MAAA,KAAA,CAAA;4BAAHH,kBAEI,CAAA,GAAA,EAFJ,UAEI,EAAAC,eAAA;AAEF,eAAAG,SAAA,EAAA,EAAAJ,kBAAA,CAwBG,MAxBH,UAwBG,EAAA;kCAvBHA,kBAsBI,CAAAK,QAAA,EAAA,IAAA,EAAAC,UAAA,CArBY,QAAM,CAAA,MAAA,EAAA,CAAf,KAAK,KAAA;uCADZN,kBAsBI,CAAA,IAAA,EAAA;oBApBH,GAAG,EAAE,KAAK,CAAC,EAAE;AACd,oBAAA,KAAK,EAACO,cAAA,CAAA,CAAA,2BAAoB,EACY,EAAA,qCAAA,EAAA,KAAA,CAAA,QAAA,EAAA,CAAA,CAAA;oBACrC,aAAW,EAAE,KAAK,CAAC,MAAM;AAC1B,oBAAA,aAAW,EAAC,0BAAyB;;8CACpCC,kBAA0D,CAAA,MAAA,EAAA;AAAtD,sBAAA,KAAM,EAAC,yBAAyB;AAAC,sBAAA,aAAW,EAAC,MAAM;;uCActD,iBAAA,EAAA;sBAZDA,kBAEO,CAAA,MAAA,EAAA;AAFD,wBAAA,KAAA,EAAA,0BAAA;AAAA,wBAAA,QAAA,EAAA,KAAA,CAAA,EAAA,CAAA,WAAA,EAAA;AACF,uBAAA,EAAAP,eAAA,CAAA,QAAA,CAAA,YAAY,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;AAEhB,sBAAA,CAAA,KAAA,CAAA,QAAA;wCAAND,kBAEO,CAAA,MAAA,EAFP,UAEO,EAAAC,eAAA,CADH,QAAa,CAAA,aAAA,CAAA,EAAA,CAAA,YAAA;;AAEjB,sBAAAO,kBAAA,CAEI,KAFJ,WAEI,EAAAP,eAAA,CADA,kBAAS,CAAC,KAAK,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,YAAA;AAEtB,sBAAA,CAAA,KAAA,CAAA,MAAA;AAAH,2BAAAG,SAAA,EAAA,EAAAJ,kBAAA,CAEE,GAFF,EAAA,WAEE,EADEC,eAAA,CAAA,KAAA,CAAA,MAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;"}
1
+ {"version":3,"file":"CnTimelineWidget.vue3.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineWidget.vue?vue&type=template&id=7ed4cc4c&lang.js"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<CnTimelineManage v-if=\"manage\"\n\t\t:register=\"resolvedRegister\"\n\t\t:schema=\"resolvedSchema\"\n\t\t:objectId=\"resolvedObjectId\"\n\t\t:apiBase=\"apiBase\"\n\t\t:content=\"content\" />\n\t<section v-else\n\t\tclass=\"cn-timeline-widget\"\n\t\tdata-testid=\"cn-timeline-widget\"\n\t\t:aria-busy=\"loading ? 'true' : 'false'\">\n\t\t<h3 v-if=\"resolvedTitle\" class=\"cn-timeline-widget__title\">\n\t\t\t{{ resolvedTitle }}\n\t\t</h3>\n\n\t\t<div v-if=\"loading && events.length === 0\" class=\"cn-timeline-widget__loading\">\n\t\t\t<NcLoadingIcon :size=\"24\" aria-hidden=\"true\" />\n\t\t\t<span>{{ loadingLabel }}</span>\n\t\t</div>\n\n\t\t<template v-else>\n\t\t\t<!-- A failed read is not an empty history: say which part is missing. -->\n\t\t\t<NcNoteCard v-if=\"failedSources.length > 0\" type=\"warning\" data-testid=\"cn-timeline-widget-error\">\n\t\t\t\t{{ failedText }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"events.length === 0\" class=\"cn-timeline-widget__empty\" data-testid=\"cn-timeline-widget-empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\n\t\t\t<ol v-else class=\"cn-timeline-widget__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"event in events\"\n\t\t\t\t\t:key=\"event.id\"\n\t\t\t\t\tclass=\"cn-timeline-widget__event\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-widget__event--upcoming': event.upcoming }\"\n\t\t\t\t\t:data-source=\"event.source\"\n\t\t\t\t\tdata-testid=\"cn-timeline-widget-event\">\n\t\t\t\t\t<span class=\"cn-timeline-widget__dot\" aria-hidden=\"true\" />\n\t\t\t\t\t<div class=\"cn-timeline-widget__body\">\n\t\t\t\t\t\t<time class=\"cn-timeline-widget__when\" :datetime=\"event.at.toISOString()\">\n\t\t\t\t\t\t\t{{ formatMoment(event) }}\n\t\t\t\t\t\t</time>\n\t\t\t\t\t\t<span v-if=\"event.upcoming\" class=\"cn-timeline-widget__badge\">\n\t\t\t\t\t\t\t{{ upcomingLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<p class=\"cn-timeline-widget__label\">\n\t\t\t\t\t\t\t{{ translate(event.label) }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"event.detail\" class=\"cn-timeline-widget__detail\">\n\t\t\t\t\t\t\t{{ event.detail }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</template>\n\t</section>\n</template>\n\n<script>\nimport { getLanguage, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport CnTimelineManage from './CnTimelineManage.vue'\nimport { auditEvents, fieldEvents, listEvents, relatedEvents, sortEvents, timelineEntryEvents } from '../../utils/timelineEvents.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnTimelineWidget — an object's dated events in time order (`timeline`\n * widget type for detail pages).\n *\n * Generalises dossiq's case timeline. It merges up to four sources, all\n * optional, into one list:\n *\n * - `fields`: the object's own date properties, `[{ field, label }]`. A\n * dotted path reaches metadata, such as `@self.created`.\n * - `related`: related objects, `[{ register?, schema, field, dateField?,\n * label, titleField? }]`. Rows of `schema` whose `field` holds this object's\n * id become events at their `dateField` (default `@self.created`).\n * - `auditTrail: true`: the object's audit trail, one event per change.\n * - `timeline: true`: OpenRegister's timeline of notes, calls and messages.\n *\n * Oldest first by default (`order: 'desc'` flips it). A moment after now is\n * marked upcoming, in words as well as style.\n *\n * `manage: true` swaps the read view for the manage view (CnTimelineManage)\n * over OpenRegister's timeline alone: kind chips, a visibility filter, pin,\n * follow-up, a note composer with standard text blocks, CSV export, and\n * `entryActions` that open a registry modal on an entry. The manage controls\n * are drawn only when the timeline read answers `canManage: true`.\n *\n * ```json\n * { \"type\": \"timeline\", \"content\": {\n * \"title\": \"Timeline\",\n * \"fields\": [\n * { \"field\": \"@self.created\", \"label\": \"Booking created\" },\n * { \"field\": \"depositClearedAt\", \"label\": \"Deposit cleared\" },\n * { \"field\": \"confirmationSentAt\", \"label\": \"Confirmation mail sent\" },\n * { \"field\": \"startsAt\", \"label\": \"Starts\" },\n * { \"field\": \"endsAt\", \"label\": \"Ends\" }\n * ] } }\n * ```\n *\n * The object comes from the detail page's context, like `audit-trail`:\n * explicit props win, then the injects, then `content`.\n *\n * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n */\nexport default {\n\tname: 'CnTimelineWidget',\n\n\tcomponents: {\n\t\tCnTimelineManage,\n\t\tNcLoadingIcon,\n\t\tNcNoteCard,\n\t},\n\n\tinject: {\n\t\t/** Detail-page object context from CnDetailPage (a ref or a raw bag). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Detail object context holder from CnPageRenderer (`{ value: { objectData, ... } }`). */\n\t\tcnDetailObjectContext: { default: null },\n\t\t/** Consumer translation function; labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Register slug; object context spread as props by CnWidgetGrid. */\n\t\tregister: { type: String, default: '' },\n\t\t/**\n\t\t * Schema slug, or the schema object the detail context supplies.\n\t\t *\n\t\t * @type {string|object}\n\t\t */\n\t\tschema: { type: [String, Object], default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** The object itself, when the host already has it. */\n\t\tobject: { type: Object, default: null },\n\t\t/** Card title override. */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Stored widget content: `{ title, fields, related, auditTrail, timeline, order, manage, entryActions, ... }`. */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: false,\n\t\t\trelatedRows: {},\n\t\t\tauditEntries: [],\n\t\t\ttimelineEntries: [],\n\t\t\tfailedSources: [],\n\t\t\tfetchedObject: null,\n\t\t\tloadSeq: 0,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tctx() {\n\t\t\tconst raw = this.cnObjectContext\n\t\t\tconst inj = raw && (raw.value !== undefined ? raw.value : raw)\n\t\t\tconst holder = this.cnDetailObjectContext && this.cnDetailObjectContext.value\n\t\t\treturn inj || holder || {}\n\t\t},\n\n\t\tresolvedObjectId() {\n\t\t\treturn this.objectId || this.ctx.objectId || this.content.objectId || ''\n\t\t},\n\n\t\tresolvedRegister() {\n\t\t\treturn this.register || this.ctx.register || this.content.register || ''\n\t\t},\n\n\t\tresolvedSchema() {\n\t\t\tconst s = this.schema || this.ctx.schema || this.content.schema || ''\n\t\t\treturn typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''\n\t\t},\n\n\t\t/**\n\t\t * The object: explicit prop, then the page context, then a fetch of\n\t\t * our own when only the id is known.\n\t\t *\n\t\t * @return {object|null}\n\t\t */\n\t\tresolvedObject() {\n\t\t\treturn this.object || this.ctx.object || this.ctx.objectData || this.fetchedObject || null\n\t\t},\n\n\t\t/**\n\t\t * Whether the manage view renders instead of the read view.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tmanage() {\n\t\t\treturn this.content.manage === true\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\tconst raw = this.title || this.content.title || ''\n\t\t\treturn raw ? this.translate(raw) : ''\n\t\t},\n\n\t\tfieldsConfig() {\n\t\t\treturn Array.isArray(this.content.fields) ? this.content.fields : []\n\t\t},\n\n\t\trelatedConfig() {\n\t\t\treturn Array.isArray(this.content.related) ? this.content.related.filter((r) => r && r.schema && r.field) : []\n\t\t},\n\n\t\t/**\n\t\t * Every event from every source, in time order.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tevents() {\n\t\t\tconst now = new Date()\n\t\t\tconst all = [\n\t\t\t\t...fieldEvents(this.resolvedObject || {}, this.fieldsConfig, now),\n\t\t\t\t...listEvents(this.resolvedObject || {}, this.content.lists, now),\n\t\t\t\t...this.relatedConfig.flatMap((cfg, i) => relatedEvents(this.relatedRows[i] || [], cfg, now)),\n\t\t\t\t...auditEvents(this.auditEntries, this.describeAudit, now),\n\t\t\t\t...timelineEntryEvents(this.timelineEntries, t('nextcloud-vue', 'Note'), now),\n\t\t\t]\n\t\t\treturn sortEvents(all, this.content.order === 'desc' ? 'desc' : 'asc')\n\t\t},\n\n\t\t/**\n\t\t * A signature of what to fetch, so a change refetches once.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tloadKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\tid: this.resolvedObjectId,\n\t\t\t\tregister: this.resolvedRegister,\n\t\t\t\tschema: this.resolvedSchema,\n\t\t\t\trelated: this.relatedConfig,\n\t\t\t\taudit: this.content.auditTrail === true,\n\t\t\t\ttimeline: this.content.timeline === true,\n\t\t\t\tneedObject: this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData),\n\t\t\t})\n\t\t},\n\n\t\tfailedText() {\n\t\t\treturn t('nextcloud-vue', 'Part of the timeline could not load: {parts}.', {\n\t\t\t\tparts: this.failedSources.map((s) => this.sourceName(s)).join(', '),\n\t\t\t})\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing has happened yet.')\n\t\t},\n\n\t\tupcomingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Upcoming')\n\t\t},\n\t},\n\n\twatch: {\n\t\tloadKey: {\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\tmethods: {\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\tsourceName(source) {\n\t\t\tif (source === 'audit') {\n\t\t\t\treturn t('nextcloud-vue', 'changes')\n\t\t\t}\n\t\t\tif (source === 'timeline') {\n\t\t\t\treturn t('nextcloud-vue', 'notes and messages')\n\t\t\t}\n\t\t\tif (source === 'object') {\n\t\t\t\treturn t('nextcloud-vue', 'dates')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'related items')\n\t\t},\n\n\t\t/**\n\t\t * The label of an audit event, from its action and who did it.\n\t\t *\n\t\t * @param {string} action The audit action (create, update, delete).\n\t\t * @param {string} actor Who did it.\n\t\t * @return {string}\n\t\t */\n\t\tdescribeAudit(action, actor) {\n\t\t\tconst known = {\n\t\t\t\tcreate: t('nextcloud-vue', 'Created'),\n\t\t\t\tupdate: t('nextcloud-vue', 'Updated'),\n\t\t\t\tdelete: t('nextcloud-vue', 'Deleted'),\n\t\t\t}\n\t\t\tconst what = known[action] || action || t('nextcloud-vue', 'Changed')\n\t\t\treturn actor ? t('nextcloud-vue', '{action} by {actor}', { action: what, actor }) : what\n\t\t},\n\n\t\t/**\n\t\t * Show a moment in the reader's language: a date for a calendar day,\n\t\t * date and time otherwise.\n\t\t *\n\t\t * @param {object} event The event.\n\t\t * @return {string}\n\t\t */\n\t\tformatMoment(event) {\n\t\t\tconst locale = (typeof getLanguage === 'function' && getLanguage()) || undefined\n\t\t\tconst options = event.dateOnly\n\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale, options).format(event.at)\n\t\t\t} catch {\n\t\t\t\treturn event.at.toLocaleString(userLocale())\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch every configured source. Each one fails on its own, so one\n\t\t * unreachable source never hides the others.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n\t\t */\n\t\tasync load() {\n\t\t\tconst id = this.resolvedObjectId\n\t\t\tconst register = this.resolvedRegister\n\t\t\tconst schema = this.resolvedSchema\n\t\t\tconst seq = ++this.loadSeq\n\t\t\tif (!id || !register || !schema || this.manage) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\timport('@nextcloud/router'),\n\t\t\t])\n\t\t\tconst base = `${this.apiBase}/objects/${register}/${schema}/${id}`\n\t\t\tconst failed = []\n\t\t\tconst jobs = []\n\n\t\t\tif (this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData)) {\n\t\t\t\tjobs.push(axios.get(generateUrl(base))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tthis.fetchedObject = (r && r.data) || null\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => failed.push('object')))\n\t\t\t}\n\n\t\t\tconst rows = {}\n\t\t\tthis.relatedConfig.forEach((cfg, i) => {\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${cfg.register || register}/${cfg.schema}`)\n\t\t\t\tjobs.push(axios.get(url, { params: { [cfg.field]: id, _limit: cfg.limit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\trows[i] = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\trows[i] = []\n\t\t\t\t\t\tif (!failed.includes('related')) {\n\t\t\t\t\t\t\tfailed.push('related')\n\t\t\t\t\t\t}\n\t\t\t\t\t}))\n\t\t\t})\n\n\t\t\tif (this.content.auditTrail === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/audit-trails`), { params: { limit: this.content.auditLimit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.auditEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.auditEntries = []\n\t\t\t\t\t\tfailed.push('audit')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (this.content.timeline === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/timeline`))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.timelineEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.timelineEntries = []\n\t\t\t\t\t\tfailed.push('timeline')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (jobs.length === 0) {\n\t\t\t\tthis.failedSources = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tawait Promise.all(jobs)\n\t\t\tif (seq !== this.loadSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.relatedRows = rows\n\t\t\tthis.failedSources = failed\n\t\t\tthis.loading = false\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-timeline-widget__title {\n\tmargin: 0;\n\tfont-size: var(--font-size-large, 1.1em);\n}\n\n.cn-timeline-widget__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__list {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-timeline-widget__event {\n\tposition: relative;\n\tdisplay: flex;\n\tgap: 12px;\n\tpadding-block-end: 12px;\n}\n\n/* The line between dots: drawn from each dot down to the next event. */\n.cn-timeline-widget__event:not(:last-child)::before {\n\tcontent: '';\n\tposition: absolute;\n\tinset-block: 14px 0;\n\tinset-inline-start: 5px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n}\n\n.cn-timeline-widget__dot {\n\tflex: 0 0 auto;\n\twidth: 12px;\n\theight: 12px;\n\tmargin-block-start: 4px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-primary-element);\n}\n\n/* Upcoming: a hollow dot, plus the word \"Upcoming\" beside the date. */\n.cn-timeline-widget__event--upcoming .cn-timeline-widget__dot {\n\tbox-sizing: border-box;\n\tborder: 2px solid var(--color-primary-element);\n\tbackground-color: var(--color-main-background);\n}\n\n.cn-timeline-widget__body {\n\tmin-width: 0;\n}\n\n.cn-timeline-widget__when {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__badge {\n\tmargin-inline-start: 8px;\n\tfont-size: var(--font-size-small, 13px);\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-widget__label {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-timeline-widget__detail {\n\tmargin: 0;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["_createElementBlock","_toDisplayString","_createVNode","_createBlock","_openBlock","_Fragment","_renderList","_normalizeClass","_createElementVNode"],"mappings":";;;;;AAeM,EAAA,KAAA,EAAA,2BAAA;;;;AAI2B,EAAA,KAAA,EAAA,6BAAA;;;;AAW3B,EAAA,KAAA,EAAA,2BAAA;AAAA,EAAA,aAAA,EAAA,0BAAA;;;;AAIQ,EAAA,KAAK,EAAE,0BAAM;;;AASjB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,0BAAe,GAAA;;;;AAInB,EAAA,KAAA,EAAA,2BAAA;;AAGH,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,2BAAA,GAAA;;;AAGA,EAAA,KAAA,EAAA,4BAAA;;;;;;;;UAhDgB,QAAA,CAAA,MAAA;+BAKF,CAAA,2BAAA,EAAA;;AAJpB,QAAA,QAAQ,EAAE,QAAgB,CAAA,gBAAA;AAC1B,QAAA,MAAM,EAAE,QAAQ,CAAA,cAAA;AAChB,QAAA,QAAQ,EAAE,QAAS,CAAA,gBAAA;AACnB,QAAA,OAAO,EAAE,MAAG,CAAA,OAAA;AACZ,QAAA,OAAO,EAAE,MAAO,CAAA,OAAA;;oBACjBA;;AACA,QAAA,KAAK,EAAC,oBAAoB;AAC1B,QAAA,aAAW,EAAC,oBAAoB;AAC/B,QAAA,WAAS,EAAE,KAAO,CAAA,OAAA,GAAA,MAAA,GAAA,OAAA;;SACf,QAAA,CAAA,aAAA;0BAAJA,kBAEK,CAAA,IAAA,EAFL,UAEK,EAAAC,eAAA;;SAEM,KAAO,CAAA,OAAA,IAAK,QAAK,CAAA,MAAA,CAAC,MAAE,KAAA,CAAA;6CAGzB,iBAAA,EAAA;cAFLC,WAAI,CAAA,wBAAA,EAAA;AAAA,gBAAA,IAAA,EAAA,EAAA;AAAA,gBAAA,aAAA,EAAA,MAAA;;;;0BAIJF;AAEY,cAAA,CAAA,KAAA,CAAA,aAAA,CAAA,MAAA,GAAA,CAAA;gCAAZG,WAEa,CAAA,qBAAA,EAAA;;AAFD,oBAAA,IAAA,EAAA,SAAA;AAAA,oBAAA,aAAA,EAAA,0BAAA;;;;;;;;AAIT,cAAA,CAAA,QAAA,CAAA,MAAA,CAAA,MAAA,KAAA,CAAA;gCAAHH,kBAEI,CAAA,GAAA,EAFJ,UAEI,EAAAC,eAAA;AAEF,mBAAAG,SAAA,EAAA,EAAAJ,kBAAA,CAwBG,MAxBH,UAwBG,EAAA;sCAvBHA,kBAsBI,CAAAK,QAAA,EAAA,IAAA,EAAAC,UAAA,CArBY,QAAM,CAAA,MAAA,EAAA,CAAf,KAAK,KAAA;2CADZN,kBAsBI,CAAA,IAAA,EAAA;wBApBH,GAAG,EAAE,KAAK,CAAC,EAAE;AACd,wBAAA,KAAK,EAACO,cAAA,CAAA,CAAA,2BAAoB,EACY,EAAA,qCAAA,EAAA,KAAA,CAAA,QAAA,EAAA,CAAA,CAAA;wBACrC,aAAW,EAAE,KAAK,CAAC,MAAM;AAC1B,wBAAA,aAAW,EAAC,0BAAyB;;kDACpCC,kBAA0D,CAAA,MAAA,EAAA;AAAtD,0BAAA,KAAM,EAAC,yBAAyB;AAAC,0BAAA,aAAW,EAAC,MAAM;;2CActD,iBAAA,EAAA;0BAZDA,kBAEO,CAAA,MAAA,EAAA;AAFD,4BAAA,KAAA,EAAA,0BAAA;AAAA,4BAAA,QAAA,EAAA,KAAA,CAAA,EAAA,CAAA,WAAA,EAAA;AACF,2BAAA,EAAAP,eAAA,CAAA,QAAA,CAAA,YAAY,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;AAEhB,0BAAA,CAAA,KAAA,CAAA,QAAA;4CAAND,kBAEO,CAAA,MAAA,EAFP,UAEO,EAAAC,eAAA,CADH,QAAa,CAAA,aAAA,CAAA,EAAA,CAAA,YAAA;;AAEjB,0BAAAO,kBAAA,CAEI,KAFJ,WAEI,EAAAP,eAAA,CADA,kBAAS,CAAC,KAAK,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,YAAA;AAEtB,0BAAA,CAAA,KAAA,CAAA,MAAA;AAAH,+BAAAG,SAAA,EAAA,EAAAJ,kBAAA,CAEE,GAFF,EAAA,WAEE,EADEC,eAAA,CAAA,KAAA,CAAA,MAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;"}
@@ -10,6 +10,7 @@ import __sfc_main$b from '../CnNoticeWidget/CnNoticeWidget.vue.js';
10
10
  import __sfc_main$6 from '../CnObjectDataWidget/CnObjectDataWidget.vue.js';
11
11
  import __sfc_main$3 from '../CnObjectGeoWidget/CnObjectGeoWidget.vue.js';
12
12
  import __sfc_main$7 from '../CnObjectMetadataWidget/CnObjectMetadataWidget.vue.js';
13
+ import __sfc_main$k from '../CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue.js';
13
14
  import __sfc_main$8 from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue.js';
14
15
  import __sfc_main$i from '../CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js';
15
16
  import __sfc_main$g from '../CnTextWidget/CnTextWidget.vue.js';
@@ -75,6 +76,10 @@ import __sfc_main from '../CnWidgetObjectTable/CnWidgetObjectTable.vue.js';
75
76
  * data — the intended remedy for a deep menu group collapsed into one
76
77
  * top-level entry via `menu-layout.json` relocations.
77
78
  *
79
+ * The `object-translations` key places CnObjectTranslationsWidget: the
80
+ * object's translatable properties per register language, with completeness
81
+ * chips and one save (register / schema / objectId via the detail-context merge).
82
+ *
78
83
  * @type {Record<string, import('vue').Component>}
79
84
  */
80
85
  const BUILT_IN_WIDGETS = {
@@ -98,6 +103,7 @@ const BUILT_IN_WIDGETS = {
98
103
  divider: __sfc_main$h,
99
104
  'saved-view-alert': __sfc_main$i,
100
105
  exports: __sfc_main$j,
106
+ 'object-translations': __sfc_main$k,
101
107
  };
102
108
 
103
109
  export { BUILT_IN_WIDGETS };
@@ -1 +1 @@
1
- {"version":3,"file":"builtInWidgets.js","sources":["../../../../src/components/CnWidgetGrid/builtInWidgets.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2024 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * builtInWidgets — internal registry of the library's built-in v2 widget components.\n *\n * Keys are the `widgetKey` values used in v2 manifests.\n * Values are the Vue component definitions.\n *\n * CnWidgetGrid resolves widget keys first against this registry, then against\n * the consumer-supplied `cnRegistry` inject. A consumer can override a built-in\n * by registering a custom component with the same key in `cnRegistry`.\n *\n * Spec: REQ-MVR-005 (manifest-v2-renderer) — widget key resolution\n */\n\nimport CnAuditTrailWidget from '../CnAuditTrailWidget/CnAuditTrailWidget.vue'\nimport CnBannerWidget from '../CnBannerWidget/CnBannerWidget.vue'\nimport CnDecisionListWidget from '../CnDecisionListWidget/CnDecisionListWidget.vue'\nimport CnDividerWidget from '../CnDividerWidget/CnDividerWidget.vue'\nimport CnExportsWidget from '../CnExportsWidget/CnExportsWidget.vue'\nimport CnHeaderWidget from '../CnHeaderWidget/CnHeaderWidget.vue'\nimport CnIntegrationWidget from '../CnIntegrationWidget/CnIntegrationWidget.vue'\nimport CnNavCardGrid from '../CnNavCardGrid/CnNavCardGrid.vue'\nimport CnNoticeWidget from '../CnNoticeWidget/CnNoticeWidget.vue'\nimport CnObjectDataWidget from '../CnObjectDataWidget/CnObjectDataWidget.vue'\nimport CnObjectGeoWidget from '../CnObjectGeoWidget/CnObjectGeoWidget.vue'\nimport CnObjectMetadataWidget from '../CnObjectMetadataWidget/CnObjectMetadataWidget.vue'\nimport CnRelatedObjectsWidget from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue'\nimport CnSavedViewAlertWidget from '../CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue'\nimport CnTextWidget from '../CnTextWidget/CnTextWidget.vue'\nimport CnTimelineWidget from '../CnTimelineWidget/CnTimelineWidget.vue'\nimport CnWidgetCardGrid from '../CnWidgetCardGrid/CnWidgetCardGrid.vue'\nimport CnWidgetFormRenderer from '../CnWidgetFormRenderer/CnWidgetFormRenderer.vue'\nimport CnWidgetMapViewer from '../CnWidgetMapViewer/CnWidgetMapViewer.vue'\nimport CnWidgetObjectTable from '../CnWidgetObjectTable/CnWidgetObjectTable.vue'\n\n/**\n * Built-in widget registry.\n *\n * The `data` and `metadata` keys are the canonical object-detail widgets:\n * a manifest `type:\"detail\"` page that places `widgetKey:\"data\"` /\n * `widgetKey:\"metadata\"` gets the object's editable property grid /\n * read-only `@self` metadata respectively. Both need the loaded object —\n * `CnPageRenderer` loads it for the detail page and `CnWidgetGrid` merges\n * `{ objectData, schema, objectType, objectId, register, store }` into each\n * widget's props (see CnWidgetGrid.resolvedWidgets), so the manifest entry\n * needs no per-widget `props`.\n *\n * The `integration` key places an OpenRegister integration leaf\n * (`CnIntegrationWidget`) on the page — e.g. Integriq's `sync-contract`\n * (\"Synced from\"). Pick the leaf with `props.only: \"<integrationId>\"`; the\n * object's `register` / `objectId` arrive via the detail-context merge, and\n * the manifest should set `props.schema` to the schema slug (the merged\n * context `schema` is the schema *object*, so an explicit slug prop wins).\n *\n * The `banner` key places a declarative notice banner (CnBannerWidget):\n * `props { variant, text, visibleWhen?, route? }` — see the component for\n * the visibleWhen predicate shape.\n *\n * The `audit-trail` key places the object change-log card\n * (CnAuditTrailWidget) — a detail-page widget whose register / schema /\n * objectId arrive via the detail-context merge (or explicit `props`).\n *\n * The `header` / `text` / `divider` keys reuse the dashboard catalog's\n * content-only presentation widgets on v2 pages: each takes a single\n * `props.content` object with the same shape their dashboard `content`\n * blob uses (see the components' docblocks).\n *\n * The `nav-card-grid` key (ADR-044 §4 cards-collapse) places CnNavCardGrid:\n * a grid of arbitrary navigation-link cards from `props.entries` (the\n * navCardEntry shape). Unlike `card-grid` (CnWidgetCardGrid, which renders\n * OpenRegister objects as CnObjectCard), `nav-card-grid` renders links, not\n * data — the intended remedy for a deep menu group collapsed into one\n * top-level entry via `menu-layout.json` relocations.\n *\n * @type {Record<string, import('vue').Component>}\n */\nexport const BUILT_IN_WIDGETS = {\n\t'object-table': CnWidgetObjectTable,\n\t'form-renderer': CnWidgetFormRenderer,\n\t'map-viewer': CnWidgetMapViewer,\n\t'object-geo': CnObjectGeoWidget,\n\t'card-grid': CnWidgetCardGrid,\n\t'nav-card-grid': CnNavCardGrid,\n\tdata: CnObjectDataWidget,\n\tmetadata: CnObjectMetadataWidget,\n\trelated: CnRelatedObjectsWidget,\n\tintegration: CnIntegrationWidget,\n\tbanner: CnBannerWidget,\n\tnotice: CnNoticeWidget,\n\t'decision-list': CnDecisionListWidget,\n\t'audit-trail': CnAuditTrailWidget,\n\ttimeline: CnTimelineWidget,\n\theader: CnHeaderWidget,\n\ttext: CnTextWidget,\n\tdivider: CnDividerWidget,\n\t'saved-view-alert': CnSavedViewAlertWidget,\n\texports: CnExportsWidget,\n}\n"],"names":["CnWidgetObjectTable","CnWidgetFormRenderer","CnWidgetMapViewer","CnObjectGeoWidget","CnWidgetCardGrid","CnNavCardGrid","CnObjectDataWidget","CnObjectMetadataWidget","CnRelatedObjectsWidget","CnIntegrationWidget","CnBannerWidget","CnNoticeWidget","CnDecisionListWidget","CnAuditTrailWidget","CnTimelineWidget","CnHeaderWidget","CnTextWidget","CnDividerWidget","CnSavedViewAlertWidget","CnExportsWidget"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,gBAAgB,GAAG;AAChC,CAAC,cAAc,EAAEA,UAAmB;AACpC,CAAC,eAAe,EAAEC,YAAoB;AACtC,CAAC,YAAY,EAAEC,YAAiB;AAChC,CAAC,YAAY,EAAEC,YAAiB;AAChC,CAAC,WAAW,EAAEC,YAAgB;AAC9B,CAAC,eAAe,EAAEC,YAAa;AAC/B,CAAC,IAAI,EAAEC,YAAkB;AACzB,CAAC,QAAQ,EAAEC,YAAsB;AACjC,CAAC,OAAO,EAAEC,YAAsB;AAChC,CAAC,WAAW,EAAEC,YAAmB;AACjC,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,eAAe,EAAEC,YAAoB;AACtC,CAAC,aAAa,EAAEC,YAAkB;AAClC,CAAC,QAAQ,EAAEC,YAAgB;AAC3B,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,IAAI,EAAEC,YAAY;AACnB,CAAC,OAAO,EAAEC,YAAe;AACzB,CAAC,kBAAkB,EAAEC,YAAsB;AAC3C,CAAC,OAAO,EAAEC,YAAe;AACzB;;;;"}
1
+ {"version":3,"file":"builtInWidgets.js","sources":["../../../../src/components/CnWidgetGrid/builtInWidgets.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2024 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * builtInWidgets — internal registry of the library's built-in v2 widget components.\n *\n * Keys are the `widgetKey` values used in v2 manifests.\n * Values are the Vue component definitions.\n *\n * CnWidgetGrid resolves widget keys first against this registry, then against\n * the consumer-supplied `cnRegistry` inject. A consumer can override a built-in\n * by registering a custom component with the same key in `cnRegistry`.\n *\n * Spec: REQ-MVR-005 (manifest-v2-renderer) — widget key resolution\n */\n\nimport CnAuditTrailWidget from '../CnAuditTrailWidget/CnAuditTrailWidget.vue'\nimport CnBannerWidget from '../CnBannerWidget/CnBannerWidget.vue'\nimport CnDecisionListWidget from '../CnDecisionListWidget/CnDecisionListWidget.vue'\nimport CnDividerWidget from '../CnDividerWidget/CnDividerWidget.vue'\nimport CnExportsWidget from '../CnExportsWidget/CnExportsWidget.vue'\nimport CnHeaderWidget from '../CnHeaderWidget/CnHeaderWidget.vue'\nimport CnIntegrationWidget from '../CnIntegrationWidget/CnIntegrationWidget.vue'\nimport CnNavCardGrid from '../CnNavCardGrid/CnNavCardGrid.vue'\nimport CnNoticeWidget from '../CnNoticeWidget/CnNoticeWidget.vue'\nimport CnObjectDataWidget from '../CnObjectDataWidget/CnObjectDataWidget.vue'\nimport CnObjectGeoWidget from '../CnObjectGeoWidget/CnObjectGeoWidget.vue'\nimport CnObjectMetadataWidget from '../CnObjectMetadataWidget/CnObjectMetadataWidget.vue'\nimport CnObjectTranslationsWidget from '../CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue'\nimport CnRelatedObjectsWidget from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue'\nimport CnSavedViewAlertWidget from '../CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue'\nimport CnTextWidget from '../CnTextWidget/CnTextWidget.vue'\nimport CnTimelineWidget from '../CnTimelineWidget/CnTimelineWidget.vue'\nimport CnWidgetCardGrid from '../CnWidgetCardGrid/CnWidgetCardGrid.vue'\nimport CnWidgetFormRenderer from '../CnWidgetFormRenderer/CnWidgetFormRenderer.vue'\nimport CnWidgetMapViewer from '../CnWidgetMapViewer/CnWidgetMapViewer.vue'\nimport CnWidgetObjectTable from '../CnWidgetObjectTable/CnWidgetObjectTable.vue'\n\n/**\n * Built-in widget registry.\n *\n * The `data` and `metadata` keys are the canonical object-detail widgets:\n * a manifest `type:\"detail\"` page that places `widgetKey:\"data\"` /\n * `widgetKey:\"metadata\"` gets the object's editable property grid /\n * read-only `@self` metadata respectively. Both need the loaded object —\n * `CnPageRenderer` loads it for the detail page and `CnWidgetGrid` merges\n * `{ objectData, schema, objectType, objectId, register, store }` into each\n * widget's props (see CnWidgetGrid.resolvedWidgets), so the manifest entry\n * needs no per-widget `props`.\n *\n * The `integration` key places an OpenRegister integration leaf\n * (`CnIntegrationWidget`) on the page — e.g. Integriq's `sync-contract`\n * (\"Synced from\"). Pick the leaf with `props.only: \"<integrationId>\"`; the\n * object's `register` / `objectId` arrive via the detail-context merge, and\n * the manifest should set `props.schema` to the schema slug (the merged\n * context `schema` is the schema *object*, so an explicit slug prop wins).\n *\n * The `banner` key places a declarative notice banner (CnBannerWidget):\n * `props { variant, text, visibleWhen?, route? }` — see the component for\n * the visibleWhen predicate shape.\n *\n * The `audit-trail` key places the object change-log card\n * (CnAuditTrailWidget) — a detail-page widget whose register / schema /\n * objectId arrive via the detail-context merge (or explicit `props`).\n *\n * The `header` / `text` / `divider` keys reuse the dashboard catalog's\n * content-only presentation widgets on v2 pages: each takes a single\n * `props.content` object with the same shape their dashboard `content`\n * blob uses (see the components' docblocks).\n *\n * The `nav-card-grid` key (ADR-044 §4 cards-collapse) places CnNavCardGrid:\n * a grid of arbitrary navigation-link cards from `props.entries` (the\n * navCardEntry shape). Unlike `card-grid` (CnWidgetCardGrid, which renders\n * OpenRegister objects as CnObjectCard), `nav-card-grid` renders links, not\n * data — the intended remedy for a deep menu group collapsed into one\n * top-level entry via `menu-layout.json` relocations.\n *\n * The `object-translations` key places CnObjectTranslationsWidget: the\n * object's translatable properties per register language, with completeness\n * chips and one save (register / schema / objectId via the detail-context merge).\n *\n * @type {Record<string, import('vue').Component>}\n */\nexport const BUILT_IN_WIDGETS = {\n\t'object-table': CnWidgetObjectTable,\n\t'form-renderer': CnWidgetFormRenderer,\n\t'map-viewer': CnWidgetMapViewer,\n\t'object-geo': CnObjectGeoWidget,\n\t'card-grid': CnWidgetCardGrid,\n\t'nav-card-grid': CnNavCardGrid,\n\tdata: CnObjectDataWidget,\n\tmetadata: CnObjectMetadataWidget,\n\trelated: CnRelatedObjectsWidget,\n\tintegration: CnIntegrationWidget,\n\tbanner: CnBannerWidget,\n\tnotice: CnNoticeWidget,\n\t'decision-list': CnDecisionListWidget,\n\t'audit-trail': CnAuditTrailWidget,\n\ttimeline: CnTimelineWidget,\n\theader: CnHeaderWidget,\n\ttext: CnTextWidget,\n\tdivider: CnDividerWidget,\n\t'saved-view-alert': CnSavedViewAlertWidget,\n\texports: CnExportsWidget,\n\t'object-translations': CnObjectTranslationsWidget,\n}\n"],"names":["CnWidgetObjectTable","CnWidgetFormRenderer","CnWidgetMapViewer","CnObjectGeoWidget","CnWidgetCardGrid","CnNavCardGrid","CnObjectDataWidget","CnObjectMetadataWidget","CnRelatedObjectsWidget","CnIntegrationWidget","CnBannerWidget","CnNoticeWidget","CnDecisionListWidget","CnAuditTrailWidget","CnTimelineWidget","CnHeaderWidget","CnTextWidget","CnDividerWidget","CnSavedViewAlertWidget","CnExportsWidget","CnObjectTranslationsWidget"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAsBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,gBAAgB,GAAG;AAChC,CAAC,cAAc,EAAEA,UAAmB;AACpC,CAAC,eAAe,EAAEC,YAAoB;AACtC,CAAC,YAAY,EAAEC,YAAiB;AAChC,CAAC,YAAY,EAAEC,YAAiB;AAChC,CAAC,WAAW,EAAEC,YAAgB;AAC9B,CAAC,eAAe,EAAEC,YAAa;AAC/B,CAAC,IAAI,EAAEC,YAAkB;AACzB,CAAC,QAAQ,EAAEC,YAAsB;AACjC,CAAC,OAAO,EAAEC,YAAsB;AAChC,CAAC,WAAW,EAAEC,YAAmB;AACjC,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,eAAe,EAAEC,YAAoB;AACtC,CAAC,aAAa,EAAEC,YAAkB;AAClC,CAAC,QAAQ,EAAEC,YAAgB;AAC3B,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,IAAI,EAAEC,YAAY;AACnB,CAAC,OAAO,EAAEC,YAAe;AACzB,CAAC,kBAAkB,EAAEC,YAAsB;AAC3C,CAAC,OAAO,EAAEC,YAAe;AACzB,CAAC,qBAAqB,EAAEC,YAA0B;AAClD;;;;"}
package/dist/esm/index.js CHANGED
@@ -33,6 +33,7 @@ export { dispatchObjectsChanged } from './utils/objectSignals.js';
33
33
  export { lensUnavailableText, readLensReports } from './utils/lensAvailability.js';
34
34
  export { isWithheld, withheldReason } from './utils/withheldValue.js';
35
35
  export { validateManifest, validateManifestV2 } from './utils/validateManifest.js';
36
+ export { validateStateMachine } from './utils/stateMachineValidation.js';
36
37
  export { clearResolveCache, resolveManifestSentinels } from './utils/resolveManifestSentinels.js';
37
38
  export { clearRouteSentinelWarnings, resolveRouteSentinels } from './utils/resolveRouteSentinels.js';
38
39
  export { SENTINEL_CONTEXTS, SENTINEL_DEPRECATIONS, SENTINEL_TOKEN_PATTERNS, SENTINEL_VOCABULARY, classifyToken, contextOf, isKnownToken, looksLikeSentinel, matchDeprecation, scanManifestTokens } from './utils/sentinelTokens.js';
@@ -63,6 +64,7 @@ export { default as CnAddWidgetModal } from './dialogs/CnAddWidgetModal.vue.js';
63
64
  export { default as CnAdminActionCard } from './components/CnAdminActionCard/CnAdminActionCard.vue.js';
64
65
  export { default as CnAdminSettingsShell } from './components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js';
65
66
  export { default as CnAdvancedFormDialog } from './components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue.js';
67
+ export { default as CnAiFeaturesWidget } from './components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue.js';
66
68
  export { default as CnApiReference } from './components/CnApiReference/CnApiReference.vue.js';
67
69
  export { default as CnAppLoading } from './components/CnAppLoading/CnAppLoading.vue.js';
68
70
  export { default as CnAppNav } from './components/CnAppNav/CnAppNav.vue.js';
@@ -272,9 +274,11 @@ export { default as CnObjectListWidgetForm } from './components/CnObjectListWidg
272
274
  export { default as CnObjectMetadataModal } from './components/CnObjectMetadataModal/CnObjectMetadataModal.vue.js';
273
275
  export { default as CnObjectMetadataWidget } from './components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue.js';
274
276
  export { default as CnObjectPartiesWidget } from './components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue.js';
277
+ export { default as CnObjectPermissionsTab } from './components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue.js';
275
278
  export { default as CnObjectPresenceWidget } from './components/CnObjectPresenceWidget/CnObjectPresenceWidget.vue.js';
276
279
  export { default as CnObjectRow } from './components/CnObjectRow/CnObjectRow.vue.js';
277
280
  export { default as CnObjectSidebar } from './components/CnObjectSidebar/CnObjectSidebar.vue.js';
281
+ export { default as CnObjectTranslationsWidget } from './components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue.js';
278
282
  export { default as CnOfflineQueue } from './components/CnOfflineQueue/CnOfflineQueue.vue.js';
279
283
  export { default as CnOrderedListField } from './components/CnOrderedListField/CnOrderedListField.vue.js';
280
284
  export { default as CnPageHeader } from './components/CnPageHeader/CnPageHeader.vue.js';
@@ -340,6 +344,7 @@ export { default as CnSpendAnalyticsWidget } from './components/CnSpendAnalytics
340
344
  export { default as CnSpendAnalyticsWidgetForm } from './components/CnSpendAnalyticsWidgetForm/CnSpendAnalyticsWidgetForm.vue.js';
341
345
  export { default as CnStagesWidget } from './components/CnStagesWidget/CnStagesWidget.vue.js';
342
346
  export { default as CnStagesWidgetForm } from './components/CnStagesWidgetForm/CnStagesWidgetForm.vue.js';
347
+ export { default as CnStateMachineEditor } from './components/CnStateMachineEditor/CnStateMachineEditor.vue.js';
343
348
  export { default as CnStatsBlock } from './components/CnStatsBlock/CnStatsBlock.vue.js';
344
349
  export { default as CnStatsBlockWidget } from './components/CnStatsBlockWidget/CnStatsBlockWidget.vue.js';
345
350
  export { default as CnStatsBlockWidgetForm } from './components/CnStatsBlockWidgetForm/CnStatsBlockWidgetForm.vue.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2020,7 +2020,164 @@ var translations = {
2020
2020
  Count: "Count",
2021
2021
  "The report could not be read.": "The report could not be read.",
2022
2022
  "Nothing to count": "Nothing to count",
2023
- "Q{quarter} {year}": "Q{quarter} {year}"
2023
+ "Q{quarter} {year}": "Q{quarter} {year}",
2024
+ "Actions for state {name}": "Actions for state {name}",
2025
+ "Add state": "Add state",
2026
+ "Add step": "Add step",
2027
+ "Arrow keys on a focused state": "Arrow keys on a focused state",
2028
+ "At least one state must stay final": "At least one state must stay final",
2029
+ "Click a state, a step or a transition to see its properties.": "Click a state, a step or a transition to see its properties.",
2030
+ "Close state properties": "Close state properties",
2031
+ "Close step properties": "Close step properties",
2032
+ "Close transition properties": "Close transition properties",
2033
+ "Connect states by dragging from one port to another, by pressing c on one state and then on another, or through a state's actions menu.": "Connect states by dragging from one port to another, by pressing c on one state and then on another, or through a state's actions menu.",
2034
+ "Connect to {name}": "Connect to {name}",
2035
+ Controls: "Controls",
2036
+ "Cycle with no way out to a final state: {names}": "Cycle with no way out to a final state: {names}",
2037
+ "Delete state": "Delete state",
2038
+ "Delete state \"{name}\"? Its steps and transitions go with it.": "Delete state \"{name}\"? Its steps and transitions go with it.",
2039
+ "Delete the transition {name}?": "Delete the transition {name}?",
2040
+ "Delete transition": "Delete transition",
2041
+ "Disconnect from {name}": "Disconnect from {name}",
2042
+ Dismiss: "Dismiss",
2043
+ "Drag a state onto the canvas to add it, or use the add button.": "Drag a state onto the canvas to add it, or use the add button.",
2044
+ "Drag the empty canvas": "Drag the empty canvas",
2045
+ "Duplicate transition from \"{from}\" to \"{to}\"": "Duplicate transition from \"{from}\" to \"{to}\"",
2046
+ "Edit transition to {name}": "Edit transition to {name}",
2047
+ Elements: "Elements",
2048
+ Final: "Final",
2049
+ "Final state \"{name}\" cannot be reached from any starting state": "Final state \"{name}\" cannot be reached from any starting state",
2050
+ Move: "Move",
2051
+ "No state is marked as final": "No state is marked as final",
2052
+ Pan: "Pan",
2053
+ "Scroll wheel or the zoom buttons": "Scroll wheel or the zoom buttons",
2054
+ "Select a state, a step or a transition to see its properties.": "Select a state, a step or a transition to see its properties.",
2055
+ "State \"{name}\" has no transitions connecting it to the others": "State \"{name}\" has no transitions connecting it to the others",
2056
+ "States and transitions": "States and transitions",
2057
+ "The state could not be deleted": "The state could not be deleted",
2058
+ Transition: "Transition",
2059
+ "Transition \"{label}\" points at a state that no longer exists": "Transition \"{label}\" points at a state that no longer exists",
2060
+ "Transition from {from} to {to}": "Transition from {from} to {to}",
2061
+ "Warning:": "Warning:",
2062
+ Zoom: "Zoom",
2063
+ required: "required",
2064
+ "State: {name}": "State: {name}",
2065
+ "Not shown": "Not shown",
2066
+ "Cannot be changed": "Cannot be changed",
2067
+ "{groups} do not see this field. {heldBy} do.": "{groups} do not see this field. {heldBy} do.",
2068
+ "{groups} do not see this field.": "{groups} do not see this field.",
2069
+ "{groups} cannot change this field. {heldBy} can.": "{groups} cannot change this field. {heldBy} can.",
2070
+ "{groups} cannot change this field.": "{groups} cannot change this field.",
2071
+ "Who holds which right": "Who holds which right",
2072
+ "Reading the grants on this record": "Reading the grants on this record",
2073
+ "You may open this record. You may not review who else can.": "You may open this record. You may not review who else can.",
2074
+ "OpenRegister could not be asked for {sources}. This list is incomplete, not empty.": "OpenRegister could not be asked for {sources}. This list is incomplete, not empty.",
2075
+ "OpenRegister reports no rule on this record.": "OpenRegister reports no rule on this record.",
2076
+ Holder: "Holder",
2077
+ Right: "Right",
2078
+ "Where it comes from": "Where it comes from",
2079
+ "Not named": "Not named",
2080
+ "OpenRegister does not publish this right.": "OpenRegister does not publish this right.",
2081
+ "Who held a right on a date": "Who held a right on a date",
2082
+ "Report the rights as they stood on": "Report the rights as they stood on",
2083
+ "Reading the trail for that date": "Reading the trail for that date",
2084
+ "The trail does not reach {date}, so nobody can be reported for it.": "The trail does not reach {date}, so nobody can be reported for it.",
2085
+ "Where it came from": "Where it came from",
2086
+ "Which fields each role reads": "Which fields each role reads",
2087
+ "A field missing from this record is missing because of a rule below, not because it is empty.": "A field missing from this record is missing because of a rule below, not because it is empty.",
2088
+ Field: "Field",
2089
+ Rule: "Rule",
2090
+ "Who it affects": "Who it affects",
2091
+ "applies to you": "applies to you",
2092
+ "These rights stood on that date. Nobody is named as setting them.": "These rights stood on that date. Nobody is named as setting them.",
2093
+ "{who} set these rights.": "{who} set these rights.",
2094
+ "{who} changed them afterwards, on {date}.": "{who} changed them afterwards, on {date}.",
2095
+ Somebody: "Somebody",
2096
+ "a date the trail does not give": "a date the trail does not give",
2097
+ "A refusal below is in force now.": "A refusal below is in force now.",
2098
+ "Refusals are switched off, so no rule below removes a right.": "Refusals are switched off, so no rule below removes a right.",
2099
+ "Refusals are staged: a rule below is recorded, and removes a right once it is switched on.": "Refusals are staged: a rule below is recorded, and removes a right once it is switched on.",
2100
+ "the rights it publishes": "the rights it publishes",
2101
+ "the shares on this record": "the shares on this record",
2102
+ "the roles": "the roles",
2103
+ "the refusals": "the refusals",
2104
+ "your own rights": "your own rights",
2105
+ "Through the role {role}": "Through the role {role}",
2106
+ "Granted on record {record}, which this one hangs under": "Granted on record {record}, which this one hangs under",
2107
+ "Written to end on {date}": "Written to end on {date}",
2108
+ "Only in {areas}": "Only in {areas}",
2109
+ "A share on this record": "A share on this record",
2110
+ "A role": "A role",
2111
+ "A grant on a group of types": "A grant on a group of types",
2112
+ "A rule on this record": "A rule on this record",
2113
+ "A rule on every record of this type": "A rule on every record of this type",
2114
+ "A rule on the register": "A rule on the register",
2115
+ "A rule that refuses": "A rule that refuses",
2116
+ "A rule that will refuse": "A rule that will refuse",
2117
+ "No rule, so it is open": "No rule, so it is open",
2118
+ "No rule grants it": "No rule grants it",
2119
+ "A grant on a record this one hangs under": "A grant on a record this one hangs under",
2120
+ "The translations could not be read. Reload the page to try again.": "The translations could not be read. Reload the page to try again.",
2121
+ "This item has no labels that can be translated.": "This item has no labels that can be translated.",
2122
+ Languages: "Languages",
2123
+ "Out of date": "Out of date",
2124
+ "{translated} of {total}": "{translated} of {total}",
2125
+ "{language} is the source. Change a {language} label and its translations are marked out of date.": "{language} is the source. Change a {language} label and its translations are marked out of date.",
2126
+ "The labels are saved.": "The labels are saved.",
2127
+ "The labels could not be saved.": "The labels could not be saved.",
2128
+ "Unavailable: hermiq does not offer this feature here.": "Unavailable: hermiq does not offer this feature here.",
2129
+ "hermiq did not say which provider runs this, or where.": "hermiq did not say which provider runs this, or where.",
2130
+ "{provider}, runs in {residency}": "{provider}, runs in {residency}",
2131
+ "No document was chosen.": "No document was chosen.",
2132
+ "{feature} reads a document, and no document was chosen.": "{feature} reads a document, and no document was chosen.",
2133
+ "{feature} will not read a document that has not been redacted.": "{feature} will not read a document that has not been redacted.",
2134
+ "{feature} did not run: {reason}": "{feature} did not run: {reason}",
2135
+ Assistant: "Assistant",
2136
+ "Reading the AI features on this record": "Reading the AI features on this record",
2137
+ Questions: "Questions",
2138
+ "The AI features on this record could not be read. This panel is incomplete, not empty.": "The AI features on this record could not be read. This panel is incomplete, not empty.",
2139
+ "The type of this record switches on no AI feature here.": "The type of this record switches on no AI feature here.",
2140
+ Document: "Document",
2141
+ "Choose a document": "Choose a document",
2142
+ "The documents on this record could not be read.": "The documents on this record could not be read.",
2143
+ "What should it do with the document?": "What should it do with the document?",
2144
+ "Gate: {gate}": "Gate: {gate}",
2145
+ "hermiq could not be reached. Nothing was run.": "hermiq could not be reached. Nothing was run.",
2146
+ "The assistant does nothing without your confirmation. It sees only what you see on this record.": "The assistant does nothing without your confirmation. It sees only what you see on this record.",
2147
+ "The assistant did not answer.": "The assistant did not answer.",
2148
+ "Your version": "Your version",
2149
+ "Use my version": "Use my version",
2150
+ "Use this": "Use this",
2151
+ Adapt: "Adapt",
2152
+ Reject: "Reject",
2153
+ "Used. Copied to your clipboard.": "Used. Copied to your clipboard.",
2154
+ "Your version is used. Copied to your clipboard.": "Your version is used. Copied to your clipboard.",
2155
+ "Rejected.": "Rejected.",
2156
+ "Your version is used.": "Your version is used.",
2157
+ "Used.": "Used.",
2158
+ "Add a note": "Add a note",
2159
+ Kind: "Kind",
2160
+ "Internal and public": "Internal and public",
2161
+ "Nothing recorded yet": "Nothing recorded yet",
2162
+ "Notes, calls and messages appear here in the order they happened.": "Notes, calls and messages appear here in the order they happened.",
2163
+ "Needs an answer": "Needs an answer",
2164
+ Unpin: "Unpin",
2165
+ Pin: "Pin",
2166
+ "Mark as answered": "Mark as answered",
2167
+ "{shown} of {total} events": "{shown} of {total} events",
2168
+ "Goes on the timeline above, internal unless you make it visible": "Goes on the timeline above, internal unless you make it visible",
2169
+ "Standard note": "Standard note",
2170
+ "Write your own": "Write your own",
2171
+ "Write a note on this record": "Write a note on this record",
2172
+ "Add to the timeline": "Add to the timeline",
2173
+ "Visible to the applicant": "Visible to the applicant",
2174
+ "Internal only": "Internal only",
2175
+ "That note could not be saved.": "That note could not be saved.",
2176
+ "The timeline could not be read. Try again, or ask an administrator to check OpenRegister.": "The timeline could not be read. Try again, or ask an administrator to check OpenRegister.",
2177
+ When: "When",
2178
+ Who: "Who",
2179
+ Message: "Message",
2180
+ "That change could not be saved.": "That change could not be saved."
2024
2181
  };
2025
2182
  var plurals = {
2026
2183
  "{count} member": [
@@ -2169,6 +2326,14 @@ var plurals = {
2169
2326
  "%n document received": [
2170
2327
  "%n document received",
2171
2328
  "%n documents received"
2329
+ ],
2330
+ "%n step": [
2331
+ "%n step",
2332
+ "%n steps"
2333
+ ],
2334
+ "Also written on %n other record": [
2335
+ "Also written on %n other record",
2336
+ "Also written on %n other records"
2172
2337
  ]
2173
2338
  };
2174
2339
  var en = {
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}