@conduction/nextcloud-vue 2.119.0 → 2.121.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 (179) 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/CnIndexPage/CnIndexPage.vue2.js +53 -1
  16. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  17. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +546 -523
  18. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  19. package/dist/esm/components/CnIndexPage/useNamedSource.js +9 -0
  20. package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
  21. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue.js +9 -0
  22. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue.js.map +1 -0
  23. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue2.js +257 -0
  24. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue2.js.map +1 -0
  25. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue3.js +266 -0
  26. package/dist/esm/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue3.js.map +1 -0
  27. package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue.js +1 -1
  28. package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue2.js +14 -7
  29. package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue2.js.map +1 -1
  30. package/dist/esm/components/CnObjectSidebar/CnObjectSidebar.vue3.js.map +1 -1
  31. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue.js +9 -0
  32. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue.js.map +1 -0
  33. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue2.js +278 -0
  34. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue2.js.map +1 -0
  35. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue3.js +128 -0
  36. package/dist/esm/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue3.js.map +1 -0
  37. package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue.js +9 -0
  38. package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue.js.map +1 -0
  39. package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue2.js +214 -0
  40. package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue2.js.map +1 -0
  41. package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue3.js +125 -0
  42. package/dist/esm/components/CnReadinessChecklist/CnReadinessChecklist.vue3.js.map +1 -0
  43. package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue.js +9 -0
  44. package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue.js.map +1 -0
  45. package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue2.js +163 -0
  46. package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue2.js.map +1 -0
  47. package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue3.js +131 -0
  48. package/dist/esm/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue3.js.map +1 -0
  49. package/dist/esm/components/CnSchemaRulesWidget/schemaRules.js +127 -0
  50. package/dist/esm/components/CnSchemaRulesWidget/schemaRules.js.map +1 -0
  51. package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue.js +9 -0
  52. package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue.js.map +1 -0
  53. package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue2.js +82 -0
  54. package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue2.js.map +1 -0
  55. package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue3.js +61 -0
  56. package/dist/esm/components/CnSearchIndexStatus/CnSearchIndexStatus.vue3.js.map +1 -0
  57. package/dist/esm/components/CnSearchIndexStatus/searchIndexStatus.js +60 -0
  58. package/dist/esm/components/CnSearchIndexStatus/searchIndexStatus.js.map +1 -0
  59. package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue.js +10 -0
  60. package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue.js.map +1 -0
  61. package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue2.js +226 -0
  62. package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue2.js.map +1 -0
  63. package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue3.js +126 -0
  64. package/dist/esm/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue3.js.map +1 -0
  65. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue.js +10 -0
  66. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue.js.map +1 -0
  67. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue2.js +944 -0
  68. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue2.js.map +1 -0
  69. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue3.js +276 -0
  70. package/dist/esm/components/CnStateMachineEditor/CnStateMachineEditor.vue3.js.map +1 -0
  71. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue.js +9 -0
  72. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue.js.map +1 -0
  73. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue2.js +354 -0
  74. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue2.js.map +1 -0
  75. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue3.js +392 -0
  76. package/dist/esm/components/CnStateMachineEditor/CnStateMachineFields.vue3.js.map +1 -0
  77. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue.js +9 -0
  78. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue.js.map +1 -0
  79. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue2.js +180 -0
  80. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue2.js.map +1 -0
  81. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue3.js +208 -0
  82. package/dist/esm/components/CnStateMachineEditor/CnStateMachineNode.vue3.js.map +1 -0
  83. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue.js +9 -0
  84. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue.js.map +1 -0
  85. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue2.js +244 -0
  86. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue2.js.map +1 -0
  87. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue3.js +76 -0
  88. package/dist/esm/components/CnStateMachineEditor/CnStateMachinePanel.vue3.js.map +1 -0
  89. package/dist/esm/components/CnStateMachineEditor/stateMachineFields.js +290 -0
  90. package/dist/esm/components/CnStateMachineEditor/stateMachineFields.js.map +1 -0
  91. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +9 -0
  92. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js.map +1 -0
  93. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js +448 -0
  94. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -0
  95. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +303 -0
  96. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -0
  97. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +1 -1
  98. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +19 -2
  99. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -1
  100. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js +73 -62
  101. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -1
  102. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +6 -0
  103. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
  104. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +42 -32
  105. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  106. package/dist/esm/composables/indexSources.js +116 -16
  107. package/dist/esm/composables/indexSources.js.map +1 -1
  108. package/dist/esm/index.js +9 -0
  109. package/dist/esm/index.js.map +1 -1
  110. package/dist/esm/l10n/en.json.js +207 -1
  111. package/dist/esm/l10n/en.json.js.map +1 -1
  112. package/dist/esm/l10n/nl.json.js +207 -1
  113. package/dist/esm/l10n/nl.json.js.map +1 -1
  114. package/dist/esm/library-style.js +1 -1
  115. package/dist/esm/nextcloud-vue.css +951 -16
  116. package/dist/esm/utils/aiFeatures.js +245 -0
  117. package/dist/esm/utils/aiFeatures.js.map +1 -0
  118. package/dist/esm/utils/aiSuggestionTracker.js +182 -0
  119. package/dist/esm/utils/aiSuggestionTracker.js.map +1 -0
  120. package/dist/esm/utils/libraryWidgetKeys.js +2 -0
  121. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  122. package/dist/esm/utils/objectPermissions.js +552 -0
  123. package/dist/esm/utils/objectPermissions.js.map +1 -0
  124. package/dist/esm/utils/objectTranslations.js +180 -0
  125. package/dist/esm/utils/objectTranslations.js.map +1 -0
  126. package/dist/esm/utils/stateMachineValidation.js +254 -0
  127. package/dist/esm/utils/stateMachineValidation.js.map +1 -0
  128. package/dist/esm/utils/widgetDispatch.js +3 -1
  129. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  130. package/dist/nextcloud-vue.cjs.js +23038 -14567
  131. package/dist/nextcloud-vue.cjs.js.map +2 -2
  132. package/dist/nextcloud-vue.css +951 -16
  133. package/l10n/en.json +207 -1
  134. package/l10n/nl.json +207 -1
  135. package/package.json +1 -1
  136. package/src/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue +416 -0
  137. package/src/components/CnAiFeaturesWidget/CnAiSuggestionDecision.vue +136 -0
  138. package/src/components/CnAiFeaturesWidget/__tests__/CnAiFeaturesWidget.spec.js +213 -0
  139. package/src/components/CnAiFeaturesWidget/index.js +14 -0
  140. package/src/components/CnIndexPage/CnIndexPage.vue +74 -3
  141. package/src/components/CnIndexPage/useNamedSource.js +9 -0
  142. package/src/components/CnObjectPermissionsTab/CnObjectPermissionsTab.vue +499 -0
  143. package/src/components/CnObjectPermissionsTab/__tests__/CnObjectPermissionsTab.spec.js +186 -0
  144. package/src/components/CnObjectPermissionsTab/index.js +13 -0
  145. package/src/components/CnObjectSidebar/CnObjectSidebar.vue +8 -1
  146. package/src/components/CnObjectTranslationsWidget/CnObjectTranslationsWidget.vue +424 -0
  147. package/src/components/CnObjectTranslationsWidget/__tests__/CnObjectTranslationsWidget.spec.js +189 -0
  148. package/src/components/CnObjectTranslationsWidget/index.js +13 -0
  149. package/src/components/CnReadinessChecklist/CnReadinessChecklist.vue +335 -0
  150. package/src/components/CnReadinessChecklist/index.js +9 -0
  151. package/src/components/CnSchemaRulesWidget/CnSchemaRulesWidget.vue +300 -0
  152. package/src/components/CnSchemaRulesWidget/index.js +10 -0
  153. package/src/components/CnSchemaRulesWidget/schemaRules.js +123 -0
  154. package/src/components/CnSearchIndexStatus/CnSearchIndexStatus.vue +160 -0
  155. package/src/components/CnSearchIndexStatus/index.js +10 -0
  156. package/src/components/CnSearchIndexStatus/searchIndexStatus.js +56 -0
  157. package/src/components/CnShippedConfigurationSection/CnShippedConfigurationSection.vue +328 -0
  158. package/src/components/CnShippedConfigurationSection/index.js +9 -0
  159. package/src/components/CnStateMachineEditor/CnStateMachineEditor.vue +1332 -0
  160. package/src/components/CnStateMachineEditor/CnStateMachineFields.vue +791 -0
  161. package/src/components/CnStateMachineEditor/CnStateMachineNode.vue +442 -0
  162. package/src/components/CnStateMachineEditor/CnStateMachinePanel.vue +326 -0
  163. package/src/components/CnStateMachineEditor/index.js +8 -0
  164. package/src/components/CnStateMachineEditor/stateMachineFields.js +287 -0
  165. package/src/components/CnTimelineWidget/CnTimelineManage.vue +827 -0
  166. package/src/components/CnTimelineWidget/CnTimelineWidget.vue +29 -3
  167. package/src/components/CnWidgetGrid/builtInWidgets.js +6 -0
  168. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +10 -0
  169. package/src/components/index.js +8 -0
  170. package/src/composables/indexSources.js +116 -16
  171. package/src/css/index-page.css +7 -0
  172. package/src/index.js +9 -0
  173. package/src/utils/aiFeatures.js +241 -0
  174. package/src/utils/aiSuggestionTracker.js +178 -0
  175. package/src/utils/libraryWidgetKeys.js +2 -0
  176. package/src/utils/objectPermissions.js +548 -0
  177. package/src/utils/objectTranslations.js +176 -0
  178. package/src/utils/stateMachineValidation.js +250 -0
  179. package/src/utils/widgetDispatch.js +3 -1
@@ -0,0 +1,9 @@
1
+ import script from './CnAiFeaturesWidget.vue2.js';
2
+ import { render } from './CnAiFeaturesWidget.vue3.js';
3
+
4
+ script.render = render;
5
+ script.__scopeId = "data-v-c7b3ee28";
6
+ const __sfc_main = script;
7
+
8
+ export { __sfc_main as default };
9
+ //# sourceMappingURL=CnAiFeaturesWidget.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnAiFeaturesWidget.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
@@ -0,0 +1,226 @@
1
+ import { translate } from '@nextcloud/l10n';
2
+ import { NcButton, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue';
3
+ import __sfc_main from './CnAiSuggestionDecision.vue.js';
4
+ import { DEFAULT_RUN_ENDPOINT, whereItRuns, fetchFeatures, fetchPrompts, fetchDocuments, askAbout, runFeatureOnDocument, AiFeatureRefusal, refusalSentence } from '../../utils/aiFeatures.js';
5
+ import { createSuggestionTracker } from '../../utils/aiSuggestionTracker.js';
6
+
7
+ var script = {
8
+ name: 'CnAiFeaturesWidget',
9
+ components: { CnAiSuggestionDecision: __sfc_main, NcButton, NcLoadingIcon, NcNoteCard, NcSelect },
10
+
11
+ props: {
12
+ /** The record id (injected by CnObjectSidebar). */
13
+ objectId: { type: String, default: '' },
14
+ /** Register slug or id (injected by CnObjectSidebar). */
15
+ register: { type: String, default: '' },
16
+ /** Schema slug or id (injected by CnObjectSidebar). */
17
+ schema: { type: String, default: '' },
18
+ /** OpenRegister API root. */
19
+ apiBase: { type: String, default: '/apps/openregister/api' },
20
+ /**
21
+ * Where the features are declared: the record's `typeField` references
22
+ * a `typeSchema` object whose `field` maps feature slug to surface;
23
+ * the slugs placed on `surface` are shown.
24
+ */
25
+ declaration: {
26
+ type: Object,
27
+ default: () => ({ typeField: '', typeSchema: '', field: 'aiFeatures', surface: '' }),
28
+ },
29
+
30
+ /** The endpoint that answers where each declared feature runs (`{features: [...]}`). */
31
+ featuresEndpoint: { type: String, default: '' },
32
+ /** Query key the declared slugs are sent under: `<key>[<slug>]=<surface>`. */
33
+ featuresQueryKey: { type: String, default: 'aiFeatures' },
34
+ /** The record's documents; empty uses OpenRegister's files of the record. */
35
+ filesEndpoint: { type: String, default: '' },
36
+ /** hermiq's run endpoint, with `{slug}`. */
37
+ runEndpoint: { type: String, default: DEFAULT_RUN_ENDPOINT },
38
+ /** Prompts offered as questions (`{prompts: [...]}`); empty offers none. */
39
+ promptsEndpoint: { type: String, default: '' },
40
+ /** Where a question is posted (`{<objectKey>: id, message}` → `{reply}`). */
41
+ askEndpoint: { type: String, default: '' },
42
+ /** The AI oversight record-action endpoint; empty reports nothing. */
43
+ decisionEndpoint: { type: String, default: '' },
44
+ /** Body key naming the record in the ask and decision bodies. */
45
+ objectKey: { type: String, default: 'objectId' },
46
+ /** Heading; empty uses "Assistant". */
47
+ title: { type: String, default: '' },
48
+ /** Whether the heading is drawn. */
49
+ showTitle: { type: Boolean, default: true },
50
+ },
51
+
52
+ data() {
53
+ return {
54
+ loading: true,
55
+ features: [],
56
+ documents: [],
57
+ runs: {},
58
+ prompts: [],
59
+ asking: false,
60
+ answer: '',
61
+ answerFailed: '',
62
+ }
63
+ },
64
+
65
+ computed: {
66
+ documentOptions() {
67
+ return (this.documents || []).map((doc) => ({ id: doc.id, label: doc.title }))
68
+ },
69
+
70
+ resolvedFilesEndpoint() {
71
+ return this.filesEndpoint
72
+ || `${this.apiBase.replace(/\/$/, '')}/objects/${this.register}/${this.schema}/${encodeURIComponent(this.objectId)}/files`
73
+ },
74
+ },
75
+
76
+ created() {
77
+ this.tracker = createSuggestionTracker({ objectId: this.objectId, objectKey: this.objectKey, endpoint: this.decisionEndpoint });
78
+ this.onPageHide = () => this.tracker.closeAll({ leaving: true });
79
+ window.addEventListener('pagehide', this.onPageHide);
80
+ },
81
+
82
+ mounted() {
83
+ this.load();
84
+ },
85
+
86
+ beforeUnmount() {
87
+ window.removeEventListener('pagehide', this.onPageHide);
88
+ this.tracker.closeAll();
89
+ },
90
+
91
+ methods: {
92
+ t: translate,
93
+ whereItRuns,
94
+
95
+ /**
96
+ * Read the features, the prompts and (when a feature can run) the documents.
97
+ *
98
+ * @return {Promise<void>}
99
+ */
100
+ async load() {
101
+ this.loading = true;
102
+ if (this.objectId === '' || !this.featuresEndpoint) {
103
+ this.features = null;
104
+ this.loading = false;
105
+ return
106
+ }
107
+
108
+ const [features, prompts] = await Promise.all([
109
+ fetchFeatures({
110
+ apiBase: this.apiBase.replace(/\/$/, ''),
111
+ register: this.register,
112
+ schema: this.schema,
113
+ objectId: this.objectId,
114
+ declaration: this.declaration,
115
+ featuresEndpoint: this.featuresEndpoint,
116
+ featuresQueryKey: this.featuresQueryKey,
117
+ }),
118
+ this.promptsEndpoint ? fetchPrompts(this.promptsEndpoint) : [],
119
+ ]);
120
+ this.features = features;
121
+ this.prompts = prompts || [];
122
+
123
+ const runs = {};
124
+ for (const feature of features || []) {
125
+ runs[feature.slug] = { documentReference: '', instruction: '', busy: false, refusal: null, failed: false, output: '' };
126
+ }
127
+ this.runs = runs;
128
+
129
+ const offersARun = (features || []).some((feature) => feature.available === true);
130
+ this.documents = offersARun ? await fetchDocuments(this.resolvedFilesEndpoint) : [];
131
+ this.loading = false;
132
+ },
133
+
134
+ selectedDocument(feature) {
135
+ const id = this.runs[feature.slug]?.documentReference;
136
+ return this.documentOptions.find((option) => option.id === id) || null
137
+ },
138
+
139
+ chooseDocument(feature, option) {
140
+ this.runs[feature.slug].documentReference = option ? String(option.id) : '';
141
+ },
142
+
143
+ /**
144
+ * Ask one of the offered prompts about this record.
145
+ *
146
+ * @param {object} prompt The prompt.
147
+ * @return {Promise<void>}
148
+ */
149
+ async ask(prompt) {
150
+ this.tracker.dismiss('question', 'superseded');
151
+ this.asking = true;
152
+ this.answer = '';
153
+ this.answerFailed = '';
154
+ try {
155
+ const result = await askAbout(this.askEndpoint, this.objectKey, this.objectId, prompt.prompt);
156
+ this.answer = String(result?.reply ?? '');
157
+ if (this.answer !== '') {
158
+ this.tracker.show('question', { type: 'qa', text: this.answer, prompt: prompt.prompt, model: String(result?.model ?? '') });
159
+ }
160
+ } catch (error) {
161
+ this.answerFailed = String(error?.response?.data?.error ?? '') || translate('nextcloud-vue', 'The assistant did not answer.');
162
+ } finally {
163
+ this.asking = false;
164
+ }
165
+ },
166
+
167
+ /**
168
+ * Report what the person did with the suggestion in a slot.
169
+ *
170
+ * @param {string} slot The slot key.
171
+ * @param {object} decision `{userAction, actualValue?}`.
172
+ * @return {Promise<void>}
173
+ */
174
+ decide(slot, decision) {
175
+ return this.tracker.decide(slot, decision.userAction, { actualValue: decision.actualValue })
176
+ },
177
+
178
+ fieldId(feature, field) {
179
+ return `cn-ai-${this.objectId || 'unknown'}-${feature.slug}-${field}`
180
+ },
181
+
182
+ /**
183
+ * Run one feature on the chosen document, and show what came back.
184
+ *
185
+ * @param {object} feature The feature.
186
+ * @return {Promise<void>}
187
+ */
188
+ async run(feature) {
189
+ const state = this.runs[feature.slug];
190
+ this.tracker.dismiss(`feature:${feature.slug}`, 'superseded');
191
+ state.busy = true;
192
+ state.refusal = null;
193
+ state.failed = false;
194
+ state.output = '';
195
+ try {
196
+ const answer = await runFeatureOnDocument({
197
+ feature: feature.slug,
198
+ documentReference: state.documentReference,
199
+ instruction: state.instruction,
200
+ runEndpoint: this.runEndpoint,
201
+ });
202
+ state.output = String(answer?.output ?? '');
203
+ if (state.output !== '') {
204
+ this.tracker.show(`feature:${feature.slug}`, {
205
+ type: 'decision_support',
206
+ text: state.output,
207
+ prompt: state.instruction,
208
+ model: String(answer?.model ?? ''),
209
+ documentId: state.documentReference,
210
+ });
211
+ }
212
+ } catch (error) {
213
+ if (error instanceof AiFeatureRefusal) {
214
+ state.refusal = { sentence: refusalSentence(error, feature.slug), gate: error.gate };
215
+ } else {
216
+ state.failed = true;
217
+ }
218
+ } finally {
219
+ state.busy = false;
220
+ }
221
+ },
222
+ },
223
+ };
224
+
225
+ export { script as default };
226
+ //# sourceMappingURL=CnAiFeaturesWidget.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnAiFeaturesWidget.vue2.js","sources":["../../../../src/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n\n CnAiFeaturesWidget — the hermiq AI features a record's type switches on for\n a surface: where each one runs (hermiq's answer; a feature hermiq does not\n offer reads unavailable, never local), a run on one of the record's\n documents with a refusal shown in words naming the feature, the reason and\n hermiq's gate, optional question prompts, and a use / adapt / reject\n decision on every suggestion for the AI oversight trail.\n-->\n<template>\n\t<div class=\"cn-ai-features\" data-testid=\"cn-ai-features\">\n\t\t<h3 v-if=\"showTitle\">\n\t\t\t{{ title || t('nextcloud-vue', 'Assistant') }}\n\t\t</h3>\n\n\t\t<div v-if=\"loading\" class=\"cn-ai-features__loading\">\n\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t{{ t('nextcloud-vue', 'Reading the AI features on this record') }}\n\t\t</div>\n\n\t\t<template v-else>\n\t\t\t<section v-if=\"prompts && prompts.length > 0\"\n\t\t\t\tclass=\"cn-ai-features__questions\"\n\t\t\t\tdata-testid=\"cn-ai-questions\">\n\t\t\t\t<h4>{{ t('nextcloud-vue', 'Questions') }}</h4>\n\t\t\t\t<ul class=\"cn-ai-features__prompts\">\n\t\t\t\t\t<li v-for=\"prompt in prompts\" :key=\"prompt.id || prompt.label\">\n\t\t\t\t\t\t<NcButton :disabled=\"asking\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-ai-question-${prompt.id}`\"\n\t\t\t\t\t\t\t@click=\"ask(prompt)\">\n\t\t\t\t\t\t\t{{ prompt.label }}\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\t<div v-if=\"answer\" class=\"cn-ai-features__output\" data-testid=\"cn-ai-question-answer\">\n\t\t\t\t\t{{ answer }}\n\t\t\t\t</div>\n\t\t\t\t<CnAiSuggestionDecision v-if=\"answer\"\n\t\t\t\t\t:text=\"answer\"\n\t\t\t\t\ttestid=\"cn-ai-question-decision\"\n\t\t\t\t\t@decide=\"decide('question', $event)\" />\n\t\t\t\t<p v-if=\"answerFailed\" class=\"cn-ai-features__unreadable\" data-testid=\"cn-ai-question-failed\">\n\t\t\t\t\t{{ answerFailed }}\n\t\t\t\t</p>\n\t\t\t</section>\n\n\t\t\t<p v-if=\"features === null\" class=\"cn-ai-features__unreadable\" data-testid=\"cn-ai-features-unreadable\">\n\t\t\t\t{{ t('nextcloud-vue', 'The AI features on this record could not be read. This panel is incomplete, not empty.') }}\n\t\t\t</p>\n\n\t\t\t<p v-else-if=\"features.length === 0\" class=\"cn-ai-features__hint\" data-testid=\"cn-ai-features-empty\">\n\t\t\t\t{{ t('nextcloud-vue', 'The type of this record switches on no AI feature here.') }}\n\t\t\t</p>\n\n\t\t\t<template v-else>\n\t\t\t\t<section v-for=\"feature in features\"\n\t\t\t\t\t:key=\"feature.slug\"\n\t\t\t\t\tclass=\"cn-ai-features__feature\"\n\t\t\t\t\t:data-testid=\"`cn-ai-feature-${feature.slug}`\">\n\t\t\t\t\t<h4>{{ feature.slug }}</h4>\n\t\t\t\t\t<p class=\"cn-ai-features__hint\" :data-testid=\"`cn-ai-feature-where-${feature.slug}`\">\n\t\t\t\t\t\t{{ whereItRuns(feature) }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<form v-if=\"feature.available === true\"\n\t\t\t\t\t\tclass=\"cn-ai-features__run\"\n\t\t\t\t\t\t@submit.prevent=\"run(feature)\">\n\t\t\t\t\t\t<NcSelect :inputId=\"fieldId(feature, 'document')\"\n\t\t\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Document')\"\n\t\t\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Choose a document')\"\n\t\t\t\t\t\t\t:options=\"documentOptions\"\n\t\t\t\t\t\t\t:modelValue=\"selectedDocument(feature)\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-document-${feature.slug}`\"\n\t\t\t\t\t\t\t@update:modelValue=\"chooseDocument(feature, $event)\" />\n\t\t\t\t\t\t<p v-if=\"documents === null\" class=\"cn-ai-features__unreadable\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'The documents on this record could not be read.') }}\n\t\t\t\t\t\t</p>\n\n\t\t\t\t\t\t<label :for=\"fieldId(feature, 'instruction')\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'What should it do with the document?') }}\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<textarea :id=\"fieldId(feature, 'instruction')\"\n\t\t\t\t\t\t\tv-model=\"runs[feature.slug].instruction\"\n\t\t\t\t\t\t\trows=\"2\" />\n\n\t\t\t\t\t\t<NcButton type=\"submit\"\n\t\t\t\t\t\t\t:disabled=\"runs[feature.slug].busy\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-run-${feature.slug}`\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Run') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</form>\n\n\t\t\t\t\t<NcNoteCard v-if=\"runs[feature.slug] && runs[feature.slug].refusal\"\n\t\t\t\t\t\ttype=\"warning\"\n\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-refusal-${feature.slug}`\">\n\t\t\t\t\t\t<p>{{ runs[feature.slug].refusal.sentence }}</p>\n\t\t\t\t\t\t<p v-if=\"runs[feature.slug].refusal.gate\" class=\"cn-ai-features__gate\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Gate: {gate}', { gate: runs[feature.slug].refusal.gate }) }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</NcNoteCard>\n\n\t\t\t\t\t<p v-if=\"runs[feature.slug] && runs[feature.slug].failed\"\n\t\t\t\t\t\tclass=\"cn-ai-features__unreadable\"\n\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-failed-${feature.slug}`\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'hermiq could not be reached. Nothing was run.') }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<div v-if=\"runs[feature.slug] && runs[feature.slug].output\"\n\t\t\t\t\t\tclass=\"cn-ai-features__output\"\n\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-output-${feature.slug}`\">\n\t\t\t\t\t\t{{ runs[feature.slug].output }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<CnAiSuggestionDecision v-if=\"runs[feature.slug] && runs[feature.slug].output\"\n\t\t\t\t\t\t:text=\"runs[feature.slug].output\"\n\t\t\t\t\t\t:testid=\"`cn-ai-feature-decision-${feature.slug}`\"\n\t\t\t\t\t\t@decide=\"decide(`feature:${feature.slug}`, $event)\" />\n\t\t\t\t</section>\n\n\t\t\t\t<p class=\"cn-ai-features__hint\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'The assistant does nothing without your confirmation. It sees only what you see on this record.') }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue'\nimport CnAiSuggestionDecision from './CnAiSuggestionDecision.vue'\nimport {\n\tAiFeatureRefusal,\n\taskAbout,\n\tDEFAULT_RUN_ENDPOINT,\n\tfetchDocuments,\n\tfetchFeatures,\n\tfetchPrompts,\n\trefusalSentence,\n\trunFeatureOnDocument,\n\twhereItRuns,\n} from '../../utils/aiFeatures.js'\nimport { createSuggestionTracker } from '../../utils/aiSuggestionTracker.js'\n\nexport default {\n\tname: 'CnAiFeaturesWidget',\n\tcomponents: { CnAiSuggestionDecision, NcButton, NcLoadingIcon, NcNoteCard, NcSelect },\n\n\tprops: {\n\t\t/** The record id (injected by CnObjectSidebar). */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** Register slug or id (injected by CnObjectSidebar). */\n\t\tregister: { type: String, default: '' },\n\t\t/** Schema slug or id (injected by CnObjectSidebar). */\n\t\tschema: { type: String, default: '' },\n\t\t/** OpenRegister API root. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/**\n\t\t * Where the features are declared: the record's `typeField` references\n\t\t * a `typeSchema` object whose `field` maps feature slug to surface;\n\t\t * the slugs placed on `surface` are shown.\n\t\t */\n\t\tdeclaration: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({ typeField: '', typeSchema: '', field: 'aiFeatures', surface: '' }),\n\t\t},\n\n\t\t/** The endpoint that answers where each declared feature runs (`{features: [...]}`). */\n\t\tfeaturesEndpoint: { type: String, default: '' },\n\t\t/** Query key the declared slugs are sent under: `<key>[<slug>]=<surface>`. */\n\t\tfeaturesQueryKey: { type: String, default: 'aiFeatures' },\n\t\t/** The record's documents; empty uses OpenRegister's files of the record. */\n\t\tfilesEndpoint: { type: String, default: '' },\n\t\t/** hermiq's run endpoint, with `{slug}`. */\n\t\trunEndpoint: { type: String, default: DEFAULT_RUN_ENDPOINT },\n\t\t/** Prompts offered as questions (`{prompts: [...]}`); empty offers none. */\n\t\tpromptsEndpoint: { type: String, default: '' },\n\t\t/** Where a question is posted (`{<objectKey>: id, message}` → `{reply}`). */\n\t\taskEndpoint: { type: String, default: '' },\n\t\t/** The AI oversight record-action endpoint; empty reports nothing. */\n\t\tdecisionEndpoint: { type: String, default: '' },\n\t\t/** Body key naming the record in the ask and decision bodies. */\n\t\tobjectKey: { type: String, default: 'objectId' },\n\t\t/** Heading; empty uses \"Assistant\". */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Whether the heading is drawn. */\n\t\tshowTitle: { type: Boolean, default: true },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: true,\n\t\t\tfeatures: [],\n\t\t\tdocuments: [],\n\t\t\truns: {},\n\t\t\tprompts: [],\n\t\t\tasking: false,\n\t\t\tanswer: '',\n\t\t\tanswerFailed: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tdocumentOptions() {\n\t\t\treturn (this.documents || []).map((doc) => ({ id: doc.id, label: doc.title }))\n\t\t},\n\n\t\tresolvedFilesEndpoint() {\n\t\t\treturn this.filesEndpoint\n\t\t\t\t|| `${this.apiBase.replace(/\\/$/, '')}/objects/${this.register}/${this.schema}/${encodeURIComponent(this.objectId)}/files`\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.tracker = createSuggestionTracker({ objectId: this.objectId, objectKey: this.objectKey, endpoint: this.decisionEndpoint })\n\t\tthis.onPageHide = () => this.tracker.closeAll({ leaving: true })\n\t\twindow.addEventListener('pagehide', this.onPageHide)\n\t},\n\n\tmounted() {\n\t\tthis.load()\n\t},\n\n\tbeforeUnmount() {\n\t\twindow.removeEventListener('pagehide', this.onPageHide)\n\t\tthis.tracker.closeAll()\n\t},\n\n\tmethods: {\n\t\tt,\n\t\twhereItRuns,\n\n\t\t/**\n\t\t * Read the features, the prompts and (when a feature can run) the documents.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tthis.loading = true\n\t\t\tif (this.objectId === '' || !this.featuresEndpoint) {\n\t\t\t\tthis.features = null\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst [features, prompts] = await Promise.all([\n\t\t\t\tfetchFeatures({\n\t\t\t\t\tapiBase: this.apiBase.replace(/\\/$/, ''),\n\t\t\t\t\tregister: this.register,\n\t\t\t\t\tschema: this.schema,\n\t\t\t\t\tobjectId: this.objectId,\n\t\t\t\t\tdeclaration: this.declaration,\n\t\t\t\t\tfeaturesEndpoint: this.featuresEndpoint,\n\t\t\t\t\tfeaturesQueryKey: this.featuresQueryKey,\n\t\t\t\t}),\n\t\t\t\tthis.promptsEndpoint ? fetchPrompts(this.promptsEndpoint) : [],\n\t\t\t])\n\t\t\tthis.features = features\n\t\t\tthis.prompts = prompts || []\n\n\t\t\tconst runs = {}\n\t\t\tfor (const feature of features || []) {\n\t\t\t\truns[feature.slug] = { documentReference: '', instruction: '', busy: false, refusal: null, failed: false, output: '' }\n\t\t\t}\n\t\t\tthis.runs = runs\n\n\t\t\tconst offersARun = (features || []).some((feature) => feature.available === true)\n\t\t\tthis.documents = offersARun ? await fetchDocuments(this.resolvedFilesEndpoint) : []\n\t\t\tthis.loading = false\n\t\t},\n\n\t\tselectedDocument(feature) {\n\t\t\tconst id = this.runs[feature.slug]?.documentReference\n\t\t\treturn this.documentOptions.find((option) => option.id === id) || null\n\t\t},\n\n\t\tchooseDocument(feature, option) {\n\t\t\tthis.runs[feature.slug].documentReference = option ? String(option.id) : ''\n\t\t},\n\n\t\t/**\n\t\t * Ask one of the offered prompts about this record.\n\t\t *\n\t\t * @param {object} prompt The prompt.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync ask(prompt) {\n\t\t\tthis.tracker.dismiss('question', 'superseded')\n\t\t\tthis.asking = true\n\t\t\tthis.answer = ''\n\t\t\tthis.answerFailed = ''\n\t\t\ttry {\n\t\t\t\tconst result = await askAbout(this.askEndpoint, this.objectKey, this.objectId, prompt.prompt)\n\t\t\t\tthis.answer = String(result?.reply ?? '')\n\t\t\t\tif (this.answer !== '') {\n\t\t\t\t\tthis.tracker.show('question', { type: 'qa', text: this.answer, prompt: prompt.prompt, model: String(result?.model ?? '') })\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.answerFailed = String(error?.response?.data?.error ?? '') || t('nextcloud-vue', 'The assistant did not answer.')\n\t\t\t} finally {\n\t\t\t\tthis.asking = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Report what the person did with the suggestion in a slot.\n\t\t *\n\t\t * @param {string} slot The slot key.\n\t\t * @param {object} decision `{userAction, actualValue?}`.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tdecide(slot, decision) {\n\t\t\treturn this.tracker.decide(slot, decision.userAction, { actualValue: decision.actualValue })\n\t\t},\n\n\t\tfieldId(feature, field) {\n\t\t\treturn `cn-ai-${this.objectId || 'unknown'}-${feature.slug}-${field}`\n\t\t},\n\n\t\t/**\n\t\t * Run one feature on the chosen document, and show what came back.\n\t\t *\n\t\t * @param {object} feature The feature.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync run(feature) {\n\t\t\tconst state = this.runs[feature.slug]\n\t\t\tthis.tracker.dismiss(`feature:${feature.slug}`, 'superseded')\n\t\t\tstate.busy = true\n\t\t\tstate.refusal = null\n\t\t\tstate.failed = false\n\t\t\tstate.output = ''\n\t\t\ttry {\n\t\t\t\tconst answer = await runFeatureOnDocument({\n\t\t\t\t\tfeature: feature.slug,\n\t\t\t\t\tdocumentReference: state.documentReference,\n\t\t\t\t\tinstruction: state.instruction,\n\t\t\t\t\trunEndpoint: this.runEndpoint,\n\t\t\t\t})\n\t\t\t\tstate.output = String(answer?.output ?? '')\n\t\t\t\tif (state.output !== '') {\n\t\t\t\t\tthis.tracker.show(`feature:${feature.slug}`, {\n\t\t\t\t\t\ttype: 'decision_support',\n\t\t\t\t\t\ttext: state.output,\n\t\t\t\t\t\tprompt: state.instruction,\n\t\t\t\t\t\tmodel: String(answer?.model ?? ''),\n\t\t\t\t\t\tdocumentId: state.documentReference,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof AiFeatureRefusal) {\n\t\t\t\t\tstate.refusal = { sentence: refusalSentence(error, feature.slug), gate: error.gate }\n\t\t\t\t} else {\n\t\t\t\t\tstate.failed = true\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tstate.busy = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-ai-features {\n\tpadding: 12px;\n}\n\n.cn-ai-features__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-ai-features__feature,\n.cn-ai-features__questions {\n\tmargin-bottom: 16px;\n\tpadding-bottom: 12px;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-ai-features__prompts {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-ai-features__run {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmargin: 8px 0;\n}\n\n.cn-ai-features__hint,\n.cn-ai-features__gate {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n.cn-ai-features__output {\n\twhite-space: pre-wrap;\n\tpadding: 8px;\n\tbackground: var(--color-background-dark);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-ai-features__unreadable {\n\tcolor: var(--color-warning-text, var(--color-main-text));\n}\n</style>\n"],"names":["CnAiSuggestionDecision","t"],"mappings":"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"}
@@ -0,0 +1,211 @@
1
+ import { resolveComponent, openBlock, createElementBlock, toDisplayString, createCommentVNode, createVNode, createTextVNode, Fragment, createElementVNode, renderList, withCtx, createBlock, withModifiers, withDirectives, vModelText } from 'vue';
2
+
3
+ const _hoisted_1 = {
4
+ class: "cn-ai-features",
5
+ "data-testid": "cn-ai-features"
6
+ };
7
+ const _hoisted_2 = { key: 0 };
8
+ const _hoisted_3 = {
9
+ key: 1,
10
+ class: "cn-ai-features__loading"
11
+ };
12
+ const _hoisted_4 = {
13
+ key: 0,
14
+ class: "cn-ai-features__questions",
15
+ "data-testid": "cn-ai-questions"
16
+ };
17
+ const _hoisted_5 = { class: "cn-ai-features__prompts" };
18
+ const _hoisted_6 = {
19
+ key: 0,
20
+ class: "cn-ai-features__output",
21
+ "data-testid": "cn-ai-question-answer"
22
+ };
23
+ const _hoisted_7 = {
24
+ key: 2,
25
+ class: "cn-ai-features__unreadable",
26
+ "data-testid": "cn-ai-question-failed"
27
+ };
28
+ const _hoisted_8 = {
29
+ key: 1,
30
+ class: "cn-ai-features__unreadable",
31
+ "data-testid": "cn-ai-features-unreadable"
32
+ };
33
+ const _hoisted_9 = {
34
+ key: 2,
35
+ class: "cn-ai-features__hint",
36
+ "data-testid": "cn-ai-features-empty"
37
+ };
38
+ const _hoisted_10 = ["data-testid"];
39
+ const _hoisted_11 = ["data-testid"];
40
+ const _hoisted_12 = ["onSubmit"];
41
+ const _hoisted_13 = {
42
+ key: 0,
43
+ class: "cn-ai-features__unreadable"
44
+ };
45
+ const _hoisted_14 = ["for"];
46
+ const _hoisted_15 = ["id", "onUpdate:modelValue"];
47
+ const _hoisted_16 = {
48
+ key: 0,
49
+ class: "cn-ai-features__gate"
50
+ };
51
+ const _hoisted_17 = ["data-testid"];
52
+ const _hoisted_18 = ["data-testid"];
53
+ const _hoisted_19 = { class: "cn-ai-features__hint" };
54
+
55
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
56
+ const _component_NcLoadingIcon = resolveComponent("NcLoadingIcon");
57
+ const _component_NcButton = resolveComponent("NcButton");
58
+ const _component_CnAiSuggestionDecision = resolveComponent("CnAiSuggestionDecision");
59
+ const _component_NcSelect = resolveComponent("NcSelect");
60
+ const _component_NcNoteCard = resolveComponent("NcNoteCard");
61
+
62
+ return (openBlock(), createElementBlock("div", _hoisted_1, [
63
+ ($props.showTitle)
64
+ ? (openBlock(), createElementBlock("h3", _hoisted_2, toDisplayString($props.title || $options.t('nextcloud-vue', 'Assistant')), 1 /* TEXT */))
65
+ : createCommentVNode("v-if", true),
66
+ ($data.loading)
67
+ ? (openBlock(), createElementBlock("div", _hoisted_3, [
68
+ createVNode(_component_NcLoadingIcon, { size: 20 }),
69
+ createTextVNode(" " + toDisplayString($options.t('nextcloud-vue', 'Reading the AI features on this record')), 1 /* TEXT */)
70
+ ]))
71
+ : (openBlock(), createElementBlock(Fragment, { key: 2 }, [
72
+ ($data.prompts && $data.prompts.length > 0)
73
+ ? (openBlock(), createElementBlock("section", _hoisted_4, [
74
+ createElementVNode("h4", null, toDisplayString($options.t('nextcloud-vue', 'Questions')), 1 /* TEXT */),
75
+ createElementVNode("ul", _hoisted_5, [
76
+ (openBlock(true), createElementBlock(Fragment, null, renderList($data.prompts, (prompt) => {
77
+ return (openBlock(), createElementBlock("li", {
78
+ key: prompt.id || prompt.label
79
+ }, [
80
+ createVNode(_component_NcButton, {
81
+ disabled: $data.asking,
82
+ "data-testid": `cn-ai-question-${prompt.id}`,
83
+ onClick: $event => ($options.ask(prompt))
84
+ }, {
85
+ default: withCtx(() => [
86
+ createTextVNode(toDisplayString(prompt.label), 1 /* TEXT */)
87
+ ]),
88
+ _: 2 /* DYNAMIC */
89
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "data-testid", "onClick"])
90
+ ]))
91
+ }), 128 /* KEYED_FRAGMENT */))
92
+ ]),
93
+ ($data.answer)
94
+ ? (openBlock(), createElementBlock("div", _hoisted_6, toDisplayString($data.answer), 1 /* TEXT */))
95
+ : createCommentVNode("v-if", true),
96
+ ($data.answer)
97
+ ? (openBlock(), createBlock(_component_CnAiSuggestionDecision, {
98
+ key: 1,
99
+ text: $data.answer,
100
+ testid: "cn-ai-question-decision",
101
+ onDecide: _cache[0] || (_cache[0] = $event => ($options.decide('question', $event)))
102
+ }, null, 8 /* PROPS */, ["text"]))
103
+ : createCommentVNode("v-if", true),
104
+ ($data.answerFailed)
105
+ ? (openBlock(), createElementBlock("p", _hoisted_7, toDisplayString($data.answerFailed), 1 /* TEXT */))
106
+ : createCommentVNode("v-if", true)
107
+ ]))
108
+ : createCommentVNode("v-if", true),
109
+ ($data.features === null)
110
+ ? (openBlock(), createElementBlock("p", _hoisted_8, toDisplayString($options.t('nextcloud-vue', 'The AI features on this record could not be read. This panel is incomplete, not empty.')), 1 /* TEXT */))
111
+ : ($data.features.length === 0)
112
+ ? (openBlock(), createElementBlock("p", _hoisted_9, toDisplayString($options.t('nextcloud-vue', 'The type of this record switches on no AI feature here.')), 1 /* TEXT */))
113
+ : (openBlock(), createElementBlock(Fragment, { key: 3 }, [
114
+ (openBlock(true), createElementBlock(Fragment, null, renderList($data.features, (feature) => {
115
+ return (openBlock(), createElementBlock("section", {
116
+ key: feature.slug,
117
+ class: "cn-ai-features__feature",
118
+ "data-testid": `cn-ai-feature-${feature.slug}`
119
+ }, [
120
+ createElementVNode("h4", null, toDisplayString(feature.slug), 1 /* TEXT */),
121
+ createElementVNode("p", {
122
+ class: "cn-ai-features__hint",
123
+ "data-testid": `cn-ai-feature-where-${feature.slug}`
124
+ }, toDisplayString($options.whereItRuns(feature)), 9 /* TEXT, PROPS */, _hoisted_11),
125
+ (feature.available === true)
126
+ ? (openBlock(), createElementBlock("form", {
127
+ key: 0,
128
+ class: "cn-ai-features__run",
129
+ onSubmit: withModifiers($event => ($options.run(feature)), ["prevent"])
130
+ }, [
131
+ createVNode(_component_NcSelect, {
132
+ inputId: $options.fieldId(feature, 'document'),
133
+ inputLabel: $options.t('nextcloud-vue', 'Document'),
134
+ placeholder: $options.t('nextcloud-vue', 'Choose a document'),
135
+ options: $options.documentOptions,
136
+ modelValue: $options.selectedDocument(feature),
137
+ "data-testid": `cn-ai-feature-document-${feature.slug}`,
138
+ "onUpdate:modelValue": $event => ($options.chooseDocument(feature, $event))
139
+ }, null, 8 /* PROPS */, ["inputId", "inputLabel", "placeholder", "options", "modelValue", "data-testid", "onUpdate:modelValue"]),
140
+ ($data.documents === null)
141
+ ? (openBlock(), createElementBlock("p", _hoisted_13, toDisplayString($options.t('nextcloud-vue', 'The documents on this record could not be read.')), 1 /* TEXT */))
142
+ : createCommentVNode("v-if", true),
143
+ createElementVNode("label", {
144
+ for: $options.fieldId(feature, 'instruction')
145
+ }, toDisplayString($options.t('nextcloud-vue', 'What should it do with the document?')), 9 /* TEXT, PROPS */, _hoisted_14),
146
+ withDirectives(createElementVNode("textarea", {
147
+ id: $options.fieldId(feature, 'instruction'),
148
+ "onUpdate:modelValue": $event => (($data.runs[feature.slug].instruction) = $event),
149
+ rows: "2"
150
+ }, null, 8 /* PROPS */, _hoisted_15), [
151
+ [vModelText, $data.runs[feature.slug].instruction]
152
+ ]),
153
+ createVNode(_component_NcButton, {
154
+ type: "submit",
155
+ disabled: $data.runs[feature.slug].busy,
156
+ "data-testid": `cn-ai-feature-run-${feature.slug}`
157
+ }, {
158
+ default: withCtx(() => [
159
+ createTextVNode(toDisplayString($options.t('nextcloud-vue', 'Run')), 1 /* TEXT */)
160
+ ]),
161
+ _: 1 /* STABLE */
162
+ }, 8 /* PROPS */, ["disabled", "data-testid"])
163
+ ], 40 /* PROPS, NEED_HYDRATION */, _hoisted_12))
164
+ : createCommentVNode("v-if", true),
165
+ ($data.runs[feature.slug] && $data.runs[feature.slug].refusal)
166
+ ? (openBlock(), createBlock(_component_NcNoteCard, {
167
+ key: 1,
168
+ type: "warning",
169
+ "data-testid": `cn-ai-feature-refusal-${feature.slug}`
170
+ }, {
171
+ default: withCtx(() => [
172
+ createElementVNode("p", null, toDisplayString($data.runs[feature.slug].refusal.sentence), 1 /* TEXT */),
173
+ ($data.runs[feature.slug].refusal.gate)
174
+ ? (openBlock(), createElementBlock("p", _hoisted_16, toDisplayString($options.t('nextcloud-vue', 'Gate: {gate}', { gate: $data.runs[feature.slug].refusal.gate })), 1 /* TEXT */))
175
+ : createCommentVNode("v-if", true)
176
+ ]),
177
+ _: 2 /* DYNAMIC */
178
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["data-testid"]))
179
+ : createCommentVNode("v-if", true),
180
+ ($data.runs[feature.slug] && $data.runs[feature.slug].failed)
181
+ ? (openBlock(), createElementBlock("p", {
182
+ key: 2,
183
+ class: "cn-ai-features__unreadable",
184
+ "data-testid": `cn-ai-feature-failed-${feature.slug}`
185
+ }, toDisplayString($options.t('nextcloud-vue', 'hermiq could not be reached. Nothing was run.')), 9 /* TEXT, PROPS */, _hoisted_17))
186
+ : createCommentVNode("v-if", true),
187
+ ($data.runs[feature.slug] && $data.runs[feature.slug].output)
188
+ ? (openBlock(), createElementBlock("div", {
189
+ key: 3,
190
+ class: "cn-ai-features__output",
191
+ "data-testid": `cn-ai-feature-output-${feature.slug}`
192
+ }, toDisplayString($data.runs[feature.slug].output), 9 /* TEXT, PROPS */, _hoisted_18))
193
+ : createCommentVNode("v-if", true),
194
+ ($data.runs[feature.slug] && $data.runs[feature.slug].output)
195
+ ? (openBlock(), createBlock(_component_CnAiSuggestionDecision, {
196
+ key: 4,
197
+ text: $data.runs[feature.slug].output,
198
+ testid: `cn-ai-feature-decision-${feature.slug}`,
199
+ onDecide: $event => ($options.decide(`feature:${feature.slug}`, $event))
200
+ }, null, 8 /* PROPS */, ["text", "testid", "onDecide"]))
201
+ : createCommentVNode("v-if", true)
202
+ ], 8 /* PROPS */, _hoisted_10))
203
+ }), 128 /* KEYED_FRAGMENT */)),
204
+ createElementVNode("p", _hoisted_19, toDisplayString($options.t('nextcloud-vue', 'The assistant does nothing without your confirmation. It sees only what you see on this record.')), 1 /* TEXT */)
205
+ ], 64 /* STABLE_FRAGMENT */))
206
+ ], 64 /* STABLE_FRAGMENT */))
207
+ ]))
208
+ }
209
+
210
+ export { render };
211
+ //# sourceMappingURL=CnAiFeaturesWidget.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnAiFeaturesWidget.vue3.js","sources":["../../../../src/components/CnAiFeaturesWidget/CnAiFeaturesWidget.vue?vue&type=template&id=c7b3ee28&lang.js"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n\n CnAiFeaturesWidget — the hermiq AI features a record's type switches on for\n a surface: where each one runs (hermiq's answer; a feature hermiq does not\n offer reads unavailable, never local), a run on one of the record's\n documents with a refusal shown in words naming the feature, the reason and\n hermiq's gate, optional question prompts, and a use / adapt / reject\n decision on every suggestion for the AI oversight trail.\n-->\n<template>\n\t<div class=\"cn-ai-features\" data-testid=\"cn-ai-features\">\n\t\t<h3 v-if=\"showTitle\">\n\t\t\t{{ title || t('nextcloud-vue', 'Assistant') }}\n\t\t</h3>\n\n\t\t<div v-if=\"loading\" class=\"cn-ai-features__loading\">\n\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t{{ t('nextcloud-vue', 'Reading the AI features on this record') }}\n\t\t</div>\n\n\t\t<template v-else>\n\t\t\t<section v-if=\"prompts && prompts.length > 0\"\n\t\t\t\tclass=\"cn-ai-features__questions\"\n\t\t\t\tdata-testid=\"cn-ai-questions\">\n\t\t\t\t<h4>{{ t('nextcloud-vue', 'Questions') }}</h4>\n\t\t\t\t<ul class=\"cn-ai-features__prompts\">\n\t\t\t\t\t<li v-for=\"prompt in prompts\" :key=\"prompt.id || prompt.label\">\n\t\t\t\t\t\t<NcButton :disabled=\"asking\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-ai-question-${prompt.id}`\"\n\t\t\t\t\t\t\t@click=\"ask(prompt)\">\n\t\t\t\t\t\t\t{{ prompt.label }}\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\t<div v-if=\"answer\" class=\"cn-ai-features__output\" data-testid=\"cn-ai-question-answer\">\n\t\t\t\t\t{{ answer }}\n\t\t\t\t</div>\n\t\t\t\t<CnAiSuggestionDecision v-if=\"answer\"\n\t\t\t\t\t:text=\"answer\"\n\t\t\t\t\ttestid=\"cn-ai-question-decision\"\n\t\t\t\t\t@decide=\"decide('question', $event)\" />\n\t\t\t\t<p v-if=\"answerFailed\" class=\"cn-ai-features__unreadable\" data-testid=\"cn-ai-question-failed\">\n\t\t\t\t\t{{ answerFailed }}\n\t\t\t\t</p>\n\t\t\t</section>\n\n\t\t\t<p v-if=\"features === null\" class=\"cn-ai-features__unreadable\" data-testid=\"cn-ai-features-unreadable\">\n\t\t\t\t{{ t('nextcloud-vue', 'The AI features on this record could not be read. This panel is incomplete, not empty.') }}\n\t\t\t</p>\n\n\t\t\t<p v-else-if=\"features.length === 0\" class=\"cn-ai-features__hint\" data-testid=\"cn-ai-features-empty\">\n\t\t\t\t{{ t('nextcloud-vue', 'The type of this record switches on no AI feature here.') }}\n\t\t\t</p>\n\n\t\t\t<template v-else>\n\t\t\t\t<section v-for=\"feature in features\"\n\t\t\t\t\t:key=\"feature.slug\"\n\t\t\t\t\tclass=\"cn-ai-features__feature\"\n\t\t\t\t\t:data-testid=\"`cn-ai-feature-${feature.slug}`\">\n\t\t\t\t\t<h4>{{ feature.slug }}</h4>\n\t\t\t\t\t<p class=\"cn-ai-features__hint\" :data-testid=\"`cn-ai-feature-where-${feature.slug}`\">\n\t\t\t\t\t\t{{ whereItRuns(feature) }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<form v-if=\"feature.available === true\"\n\t\t\t\t\t\tclass=\"cn-ai-features__run\"\n\t\t\t\t\t\t@submit.prevent=\"run(feature)\">\n\t\t\t\t\t\t<NcSelect :inputId=\"fieldId(feature, 'document')\"\n\t\t\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Document')\"\n\t\t\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Choose a document')\"\n\t\t\t\t\t\t\t:options=\"documentOptions\"\n\t\t\t\t\t\t\t:modelValue=\"selectedDocument(feature)\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-document-${feature.slug}`\"\n\t\t\t\t\t\t\t@update:modelValue=\"chooseDocument(feature, $event)\" />\n\t\t\t\t\t\t<p v-if=\"documents === null\" class=\"cn-ai-features__unreadable\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'The documents on this record could not be read.') }}\n\t\t\t\t\t\t</p>\n\n\t\t\t\t\t\t<label :for=\"fieldId(feature, 'instruction')\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'What should it do with the document?') }}\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<textarea :id=\"fieldId(feature, 'instruction')\"\n\t\t\t\t\t\t\tv-model=\"runs[feature.slug].instruction\"\n\t\t\t\t\t\t\trows=\"2\" />\n\n\t\t\t\t\t\t<NcButton type=\"submit\"\n\t\t\t\t\t\t\t:disabled=\"runs[feature.slug].busy\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-run-${feature.slug}`\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Run') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</form>\n\n\t\t\t\t\t<NcNoteCard v-if=\"runs[feature.slug] && runs[feature.slug].refusal\"\n\t\t\t\t\t\ttype=\"warning\"\n\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-refusal-${feature.slug}`\">\n\t\t\t\t\t\t<p>{{ runs[feature.slug].refusal.sentence }}</p>\n\t\t\t\t\t\t<p v-if=\"runs[feature.slug].refusal.gate\" class=\"cn-ai-features__gate\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Gate: {gate}', { gate: runs[feature.slug].refusal.gate }) }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</NcNoteCard>\n\n\t\t\t\t\t<p v-if=\"runs[feature.slug] && runs[feature.slug].failed\"\n\t\t\t\t\t\tclass=\"cn-ai-features__unreadable\"\n\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-failed-${feature.slug}`\">\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'hermiq could not be reached. Nothing was run.') }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<div v-if=\"runs[feature.slug] && runs[feature.slug].output\"\n\t\t\t\t\t\tclass=\"cn-ai-features__output\"\n\t\t\t\t\t\t:data-testid=\"`cn-ai-feature-output-${feature.slug}`\">\n\t\t\t\t\t\t{{ runs[feature.slug].output }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<CnAiSuggestionDecision v-if=\"runs[feature.slug] && runs[feature.slug].output\"\n\t\t\t\t\t\t:text=\"runs[feature.slug].output\"\n\t\t\t\t\t\t:testid=\"`cn-ai-feature-decision-${feature.slug}`\"\n\t\t\t\t\t\t@decide=\"decide(`feature:${feature.slug}`, $event)\" />\n\t\t\t\t</section>\n\n\t\t\t\t<p class=\"cn-ai-features__hint\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'The assistant does nothing without your confirmation. It sees only what you see on this record.') }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon, NcNoteCard, NcSelect } from '@nextcloud/vue'\nimport CnAiSuggestionDecision from './CnAiSuggestionDecision.vue'\nimport {\n\tAiFeatureRefusal,\n\taskAbout,\n\tDEFAULT_RUN_ENDPOINT,\n\tfetchDocuments,\n\tfetchFeatures,\n\tfetchPrompts,\n\trefusalSentence,\n\trunFeatureOnDocument,\n\twhereItRuns,\n} from '../../utils/aiFeatures.js'\nimport { createSuggestionTracker } from '../../utils/aiSuggestionTracker.js'\n\nexport default {\n\tname: 'CnAiFeaturesWidget',\n\tcomponents: { CnAiSuggestionDecision, NcButton, NcLoadingIcon, NcNoteCard, NcSelect },\n\n\tprops: {\n\t\t/** The record id (injected by CnObjectSidebar). */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** Register slug or id (injected by CnObjectSidebar). */\n\t\tregister: { type: String, default: '' },\n\t\t/** Schema slug or id (injected by CnObjectSidebar). */\n\t\tschema: { type: String, default: '' },\n\t\t/** OpenRegister API root. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/**\n\t\t * Where the features are declared: the record's `typeField` references\n\t\t * a `typeSchema` object whose `field` maps feature slug to surface;\n\t\t * the slugs placed on `surface` are shown.\n\t\t */\n\t\tdeclaration: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({ typeField: '', typeSchema: '', field: 'aiFeatures', surface: '' }),\n\t\t},\n\n\t\t/** The endpoint that answers where each declared feature runs (`{features: [...]}`). */\n\t\tfeaturesEndpoint: { type: String, default: '' },\n\t\t/** Query key the declared slugs are sent under: `<key>[<slug>]=<surface>`. */\n\t\tfeaturesQueryKey: { type: String, default: 'aiFeatures' },\n\t\t/** The record's documents; empty uses OpenRegister's files of the record. */\n\t\tfilesEndpoint: { type: String, default: '' },\n\t\t/** hermiq's run endpoint, with `{slug}`. */\n\t\trunEndpoint: { type: String, default: DEFAULT_RUN_ENDPOINT },\n\t\t/** Prompts offered as questions (`{prompts: [...]}`); empty offers none. */\n\t\tpromptsEndpoint: { type: String, default: '' },\n\t\t/** Where a question is posted (`{<objectKey>: id, message}` → `{reply}`). */\n\t\taskEndpoint: { type: String, default: '' },\n\t\t/** The AI oversight record-action endpoint; empty reports nothing. */\n\t\tdecisionEndpoint: { type: String, default: '' },\n\t\t/** Body key naming the record in the ask and decision bodies. */\n\t\tobjectKey: { type: String, default: 'objectId' },\n\t\t/** Heading; empty uses \"Assistant\". */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Whether the heading is drawn. */\n\t\tshowTitle: { type: Boolean, default: true },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: true,\n\t\t\tfeatures: [],\n\t\t\tdocuments: [],\n\t\t\truns: {},\n\t\t\tprompts: [],\n\t\t\tasking: false,\n\t\t\tanswer: '',\n\t\t\tanswerFailed: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tdocumentOptions() {\n\t\t\treturn (this.documents || []).map((doc) => ({ id: doc.id, label: doc.title }))\n\t\t},\n\n\t\tresolvedFilesEndpoint() {\n\t\t\treturn this.filesEndpoint\n\t\t\t\t|| `${this.apiBase.replace(/\\/$/, '')}/objects/${this.register}/${this.schema}/${encodeURIComponent(this.objectId)}/files`\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.tracker = createSuggestionTracker({ objectId: this.objectId, objectKey: this.objectKey, endpoint: this.decisionEndpoint })\n\t\tthis.onPageHide = () => this.tracker.closeAll({ leaving: true })\n\t\twindow.addEventListener('pagehide', this.onPageHide)\n\t},\n\n\tmounted() {\n\t\tthis.load()\n\t},\n\n\tbeforeUnmount() {\n\t\twindow.removeEventListener('pagehide', this.onPageHide)\n\t\tthis.tracker.closeAll()\n\t},\n\n\tmethods: {\n\t\tt,\n\t\twhereItRuns,\n\n\t\t/**\n\t\t * Read the features, the prompts and (when a feature can run) the documents.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tthis.loading = true\n\t\t\tif (this.objectId === '' || !this.featuresEndpoint) {\n\t\t\t\tthis.features = null\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst [features, prompts] = await Promise.all([\n\t\t\t\tfetchFeatures({\n\t\t\t\t\tapiBase: this.apiBase.replace(/\\/$/, ''),\n\t\t\t\t\tregister: this.register,\n\t\t\t\t\tschema: this.schema,\n\t\t\t\t\tobjectId: this.objectId,\n\t\t\t\t\tdeclaration: this.declaration,\n\t\t\t\t\tfeaturesEndpoint: this.featuresEndpoint,\n\t\t\t\t\tfeaturesQueryKey: this.featuresQueryKey,\n\t\t\t\t}),\n\t\t\t\tthis.promptsEndpoint ? fetchPrompts(this.promptsEndpoint) : [],\n\t\t\t])\n\t\t\tthis.features = features\n\t\t\tthis.prompts = prompts || []\n\n\t\t\tconst runs = {}\n\t\t\tfor (const feature of features || []) {\n\t\t\t\truns[feature.slug] = { documentReference: '', instruction: '', busy: false, refusal: null, failed: false, output: '' }\n\t\t\t}\n\t\t\tthis.runs = runs\n\n\t\t\tconst offersARun = (features || []).some((feature) => feature.available === true)\n\t\t\tthis.documents = offersARun ? await fetchDocuments(this.resolvedFilesEndpoint) : []\n\t\t\tthis.loading = false\n\t\t},\n\n\t\tselectedDocument(feature) {\n\t\t\tconst id = this.runs[feature.slug]?.documentReference\n\t\t\treturn this.documentOptions.find((option) => option.id === id) || null\n\t\t},\n\n\t\tchooseDocument(feature, option) {\n\t\t\tthis.runs[feature.slug].documentReference = option ? String(option.id) : ''\n\t\t},\n\n\t\t/**\n\t\t * Ask one of the offered prompts about this record.\n\t\t *\n\t\t * @param {object} prompt The prompt.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync ask(prompt) {\n\t\t\tthis.tracker.dismiss('question', 'superseded')\n\t\t\tthis.asking = true\n\t\t\tthis.answer = ''\n\t\t\tthis.answerFailed = ''\n\t\t\ttry {\n\t\t\t\tconst result = await askAbout(this.askEndpoint, this.objectKey, this.objectId, prompt.prompt)\n\t\t\t\tthis.answer = String(result?.reply ?? '')\n\t\t\t\tif (this.answer !== '') {\n\t\t\t\t\tthis.tracker.show('question', { type: 'qa', text: this.answer, prompt: prompt.prompt, model: String(result?.model ?? '') })\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.answerFailed = String(error?.response?.data?.error ?? '') || t('nextcloud-vue', 'The assistant did not answer.')\n\t\t\t} finally {\n\t\t\t\tthis.asking = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Report what the person did with the suggestion in a slot.\n\t\t *\n\t\t * @param {string} slot The slot key.\n\t\t * @param {object} decision `{userAction, actualValue?}`.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tdecide(slot, decision) {\n\t\t\treturn this.tracker.decide(slot, decision.userAction, { actualValue: decision.actualValue })\n\t\t},\n\n\t\tfieldId(feature, field) {\n\t\t\treturn `cn-ai-${this.objectId || 'unknown'}-${feature.slug}-${field}`\n\t\t},\n\n\t\t/**\n\t\t * Run one feature on the chosen document, and show what came back.\n\t\t *\n\t\t * @param {object} feature The feature.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync run(feature) {\n\t\t\tconst state = this.runs[feature.slug]\n\t\t\tthis.tracker.dismiss(`feature:${feature.slug}`, 'superseded')\n\t\t\tstate.busy = true\n\t\t\tstate.refusal = null\n\t\t\tstate.failed = false\n\t\t\tstate.output = ''\n\t\t\ttry {\n\t\t\t\tconst answer = await runFeatureOnDocument({\n\t\t\t\t\tfeature: feature.slug,\n\t\t\t\t\tdocumentReference: state.documentReference,\n\t\t\t\t\tinstruction: state.instruction,\n\t\t\t\t\trunEndpoint: this.runEndpoint,\n\t\t\t\t})\n\t\t\t\tstate.output = String(answer?.output ?? '')\n\t\t\t\tif (state.output !== '') {\n\t\t\t\t\tthis.tracker.show(`feature:${feature.slug}`, {\n\t\t\t\t\t\ttype: 'decision_support',\n\t\t\t\t\t\ttext: state.output,\n\t\t\t\t\t\tprompt: state.instruction,\n\t\t\t\t\t\tmodel: String(answer?.model ?? ''),\n\t\t\t\t\t\tdocumentId: state.documentReference,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof AiFeatureRefusal) {\n\t\t\t\t\tstate.refusal = { sentence: refusalSentence(error, feature.slug), gate: error.gate }\n\t\t\t\t} else {\n\t\t\t\t\tstate.failed = true\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tstate.busy = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-ai-features {\n\tpadding: 12px;\n}\n\n.cn-ai-features__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-ai-features__feature,\n.cn-ai-features__questions {\n\tmargin-bottom: 16px;\n\tpadding-bottom: 12px;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-ai-features__prompts {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-ai-features__run {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmargin: 8px 0;\n}\n\n.cn-ai-features__hint,\n.cn-ai-features__gate {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n.cn-ai-features__output {\n\twhite-space: pre-wrap;\n\tpadding: 8px;\n\tbackground: var(--color-background-dark);\n\tborder-radius: var(--border-radius);\n}\n\n.cn-ai-features__unreadable {\n\tcolor: var(--color-warning-text, var(--color-main-text));\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_toDisplayString","_createTextVNode","_createElementVNode","_Fragment","_renderList","_createVNode","_createBlock","_vModelText"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import script from './CnAiSuggestionDecision.vue2.js';
2
+ import { render } from './CnAiSuggestionDecision.vue3.js';
3
+
4
+ script.render = render;
5
+ script.__scopeId = "data-v-77db0b7a";
6
+ const __sfc_main = script;
7
+
8
+ export { __sfc_main as default };
9
+ //# sourceMappingURL=CnAiSuggestionDecision.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnAiSuggestionDecision.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
@@ -0,0 +1,64 @@
1
+ import { translate } from '@nextcloud/l10n';
2
+ import { NcButton } from '@nextcloud/vue';
3
+
4
+ var script = {
5
+ name: 'CnAiSuggestionDecision',
6
+ components: { NcButton },
7
+
8
+ props: {
9
+ /** The suggestion text. */
10
+ text: { type: String, required: true },
11
+ /** Test id prefix, also the base of the draft field id. */
12
+ testid: { type: String, default: 'cn-ai-suggestion-decision' },
13
+ },
14
+
15
+ emits: ['decide'],
16
+
17
+ data() {
18
+ return { editing: false, draft: '', decided: '' }
19
+ },
20
+
21
+ watch: {
22
+ text() {
23
+ this.editing = false;
24
+ this.draft = '';
25
+ this.decided = '';
26
+ },
27
+ },
28
+
29
+ methods: {
30
+ t: translate,
31
+
32
+ startEditing() {
33
+ this.draft = this.text;
34
+ this.editing = true;
35
+ },
36
+
37
+ /**
38
+ * Report the decision, and copy a used suggestion to the clipboard.
39
+ *
40
+ * @param {string} userAction accepted, modified or rejected.
41
+ * @return {Promise<void>}
42
+ */
43
+ async decide(userAction) {
44
+ const used = userAction === 'modified' ? this.draft : this.text;
45
+ this.$emit('decide', { userAction, actualValue: userAction === 'modified' ? this.draft : undefined });
46
+ this.decided = {
47
+ accepted: translate('nextcloud-vue', 'Used. Copied to your clipboard.'),
48
+ modified: translate('nextcloud-vue', 'Your version is used. Copied to your clipboard.'),
49
+ rejected: translate('nextcloud-vue', 'Rejected.'),
50
+ }[userAction];
51
+ if (userAction === 'rejected') {
52
+ return
53
+ }
54
+ try {
55
+ await navigator.clipboard.writeText(used);
56
+ } catch {
57
+ this.decided = userAction === 'modified' ? translate('nextcloud-vue', 'Your version is used.') : translate('nextcloud-vue', 'Used.');
58
+ }
59
+ },
60
+ },
61
+ };
62
+
63
+ export { script as default };
64
+ //# sourceMappingURL=CnAiSuggestionDecision.vue2.js.map