@conduction/nextcloud-vue 2.69.0 → 2.71.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 (153) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +25 -0
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +155 -152
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +77 -0
  6. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  7. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +8 -8
  8. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +151 -13
  10. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  11. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +3 -1
  12. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  13. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue.js +1 -0
  14. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue.js.map +1 -1
  15. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +28 -0
  16. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
  17. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +4 -2
  18. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
  19. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js +25 -1
  20. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js.map +1 -1
  21. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js +32 -17
  22. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js.map +1 -1
  23. package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue2.js +14 -1
  24. package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue2.js.map +1 -1
  25. package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue3.js.map +1 -1
  26. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +43 -2
  27. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
  28. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +3 -3
  29. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
  30. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +25 -1
  31. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  32. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +40 -43
  33. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  34. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +35 -1
  35. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  36. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  37. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +54 -3
  38. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  39. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +6 -3
  40. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  41. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +28 -0
  42. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  43. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +3 -2
  44. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  45. package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue2.js +12 -0
  46. package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +9 -0
  48. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  49. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  50. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +29 -2
  51. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  52. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +71 -34
  53. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  54. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +54 -7
  55. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  56. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +26 -8
  57. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  58. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +165 -0
  59. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  60. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +69 -26
  61. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  62. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js.map +1 -1
  63. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js.map +1 -1
  64. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +4 -1
  65. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  66. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  67. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +1 -1
  68. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
  69. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
  70. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  71. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +46 -32
  72. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  73. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +17 -3
  74. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -1
  75. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +25 -24
  76. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -1
  77. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  78. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  79. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +27 -0
  80. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  81. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +7 -0
  82. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  83. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +24 -1
  84. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
  85. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js +1 -1
  86. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
  87. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +11 -0
  88. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
  89. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +4 -2
  90. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
  91. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +30 -9
  92. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
  93. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
  94. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +15 -2
  95. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
  96. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js +31 -32
  97. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
  98. package/dist/esm/composables/useWalkthrough.js +11 -3
  99. package/dist/esm/composables/useWalkthrough.js.map +1 -1
  100. package/dist/esm/nextcloud-vue.css +198 -0
  101. package/dist/esm/utils/capabilityComparison.js +29 -1
  102. package/dist/esm/utils/capabilityComparison.js.map +1 -1
  103. package/dist/esm/utils/columnFilters.js +54 -4
  104. package/dist/esm/utils/columnFilters.js.map +1 -1
  105. package/dist/esm/utils/userAutocomplete.js +69 -3
  106. package/dist/esm/utils/userAutocomplete.js.map +1 -1
  107. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  108. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  109. package/dist/nextcloud-vue.cjs.js +2778 -1630
  110. package/dist/nextcloud-vue.cjs.js.map +2 -2
  111. package/dist/nextcloud-vue.css +198 -0
  112. package/package.json +1 -1
  113. package/src/components/CnActionsBar/CnActionsBar.md +2 -0
  114. package/src/components/CnActionsBar/CnActionsBar.vue +28 -2
  115. package/src/components/CnAppNav/CnAppNav.vue +85 -8
  116. package/src/components/CnAppRoot/CnAppRoot.vue +153 -13
  117. package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +45 -0
  118. package/src/components/CnCalendarWidget/CnCalendarWidget.vue +32 -4
  119. package/src/components/CnCapabilityTable/CnCapabilityTable.vue +14 -0
  120. package/src/components/CnDashboardGrid/CnDashboardGrid.md +2 -0
  121. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +54 -2
  122. package/src/components/CnDashboardPage/CnDashboardPage.vue +46 -19
  123. package/src/components/CnDataTable/CnDataTable.vue +35 -1
  124. package/src/components/CnDetailPage/CnDetailPage.md +2 -0
  125. package/src/components/CnDetailPage/CnDetailPage.vue +57 -3
  126. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +30 -1
  127. package/src/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue +12 -0
  128. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +9 -0
  129. package/src/components/CnFormDialog/CnFormDialog.vue +62 -2
  130. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +95 -8
  131. package/src/components/CnIndexPage/CnIndexPage.vue +194 -7
  132. package/src/components/CnNextStepCard/CnNextStepCard.vue +11 -0
  133. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +4 -1
  134. package/src/components/CnObjectSidebar/CnNotesTab.vue +1 -1
  135. package/src/components/CnSetupWizard/CnSetupWizard.vue +7 -0
  136. package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +34 -7
  137. package/src/components/CnStagesWidget/CnStagesWidget.vue +19 -0
  138. package/src/components/CnStatWidget/CnStatWidget.vue +36 -0
  139. package/src/components/CnStatsBlock/CnStatsBlock.md +2 -0
  140. package/src/components/CnStatsBlock/CnStatsBlock.vue +25 -2
  141. package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +13 -0
  142. package/src/components/CnWalkthrough/CnWalkthrough.vue +30 -9
  143. package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +24 -3
  144. package/src/composables/useWalkthrough.js +11 -3
  145. package/src/css/dashboard.css +44 -0
  146. package/src/css/detail-page.css +10 -0
  147. package/src/css/index-page.css +12 -0
  148. package/src/css/kpi-card.css +15 -0
  149. package/src/schemas/app-manifest-v2.schema.json +47 -5
  150. package/src/utils/capabilityComparison.js +28 -0
  151. package/src/utils/columnFilters.js +54 -4
  152. package/src/utils/userAutocomplete.js +68 -2
  153. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -1,3 +1,4 @@
1
+ import { getCurrentUser } from '@nextcloud/auth';
1
2
  import axios__default from '@nextcloud/axios';
2
3
  import { generateOcsUrl } from '@nextcloud/router';
3
4
 
@@ -16,6 +17,46 @@ import { generateOcsUrl } from '@nextcloud/router';
16
17
  */
17
18
 
18
19
 
20
+ /**
21
+ * The signed-in user as a picker option, or null when nobody is signed in.
22
+ *
23
+ * Core autocomplete never returns the person who searches (it is built for
24
+ * sharing, and you do not share with yourself), so a picker backed by it
25
+ * alone cannot assign a task to yourself.
26
+ *
27
+ * @spec openspec/changes/audit-round-lib-fixes/specs/schema-utilities/spec.md
28
+ * @return {{id: string, label: string, displayName: string, subline: string}|null} The option.
29
+ */
30
+ function currentUserOption() {
31
+ let user;
32
+ try {
33
+ user = getCurrentUser();
34
+ } catch {
35
+ return null
36
+ }
37
+ if (!user || !user.uid) {
38
+ return null
39
+ }
40
+ const name = user.displayName || String(user.uid);
41
+ return { id: String(user.uid), label: name, displayName: name, subline: '' }
42
+ }
43
+
44
+ /**
45
+ * Whether the current-user option matches a search term (uid or display
46
+ * name contains the term, ignoring case). An empty term matches.
47
+ *
48
+ * @param {object} option The current-user option.
49
+ * @param {string} query The search term.
50
+ * @return {boolean} True when it matches.
51
+ */
52
+ function matchesQuery(option, query) {
53
+ const q = String(query || '').trim().toLowerCase();
54
+ if (q === '') {
55
+ return true
56
+ }
57
+ return option.id.toLowerCase().includes(q) || option.label.toLowerCase().includes(q)
58
+ }
59
+
19
60
  /**
20
61
  * Map one autocomplete suggestion to a picker option, keeping only user
21
62
  * results. The OCS payload uses `id` for the UID, `label` for the display
@@ -60,10 +101,11 @@ function toUserOption(suggestion) {
60
101
  * @param {string} [query] The search term (empty loads an initial page).
61
102
  * @param {object} [options] Tuning options.
62
103
  * @param {number} [options.limit] Max results (default 25).
104
+ * @param {boolean} [options.includeCurrentUser] Add the signed-in user when they match (default true; a mention list passes false).
63
105
  * @return {Promise<Array<{id: string, label: string, subline: string}>>} Picker options.
64
106
  */
65
107
  async function searchNextcloudUsers(query = '', options = {}) {
66
- const { limit = 25 } = options;
108
+ const { limit = 25, includeCurrentUser = true } = options;
67
109
  try {
68
110
  const url = generateOcsUrl('core/autocomplete/get');
69
111
  const response = await axios__default.get(url, {
@@ -87,14 +129,32 @@ async function searchNextcloudUsers(query = '', options = {}) {
87
129
  const list = Array.isArray(data)
88
130
  ? data
89
131
  : (Array.isArray(response && response.data) ? response.data : []);
90
- return list
132
+ const found = list
91
133
  .map(toUserOption)
92
- .filter((opt) => opt !== null)
134
+ .filter((opt) => opt !== null);
135
+ return includeCurrentUser ? withCurrentUser(found, query) : found
93
136
  } catch {
94
137
  return []
95
138
  }
96
139
  }
97
140
 
141
+ /**
142
+ * Put the signed-in user first in a result list when they match the search
143
+ * and the server left them out.
144
+ *
145
+ * @spec openspec/changes/audit-round-lib-fixes/specs/schema-utilities/spec.md
146
+ * @param {Array<object>} options The server's options.
147
+ * @param {string} query The search term.
148
+ * @return {Array<object>} The options, the current user included when they match.
149
+ */
150
+ function withCurrentUser(options, query) {
151
+ const me = currentUserOption();
152
+ if (!me || !matchesQuery(me, query) || options.some((opt) => opt.id === me.id)) {
153
+ return options
154
+ }
155
+ return [me, ...options]
156
+ }
157
+
98
158
  /**
99
159
  * Resolve a single user UID to a `{ id, label }` option for edit-mode display.
100
160
  * Tries the autocomplete endpoint with the UID as the query and matches the
@@ -109,6 +169,12 @@ async function resolveNextcloudUser(uid) {
109
169
  if (uid === undefined || uid === null || uid === '') {
110
170
  return fallback
111
171
  }
172
+ // The server never returns the signed-in user, so their own uid would
173
+ // otherwise fall back to the bare uid.
174
+ const me = currentUserOption();
175
+ if (me && me.id === String(uid)) {
176
+ return me
177
+ }
112
178
  const results = await searchNextcloudUsers(String(uid));
113
179
  const match = results.find((opt) => opt.id === String(uid));
114
180
  return match || fallback
@@ -1 +1 @@
1
- {"version":3,"file":"userAutocomplete.js","sources":["../../../src/utils/userAutocomplete.js"],"sourcesContent":["/**\n * Nextcloud user autocomplete helpers.\n *\n * Resolves real Nextcloud users for the schema-driven form's user-picker\n * (a property marked `referenceType: 'nextcloud-user'` or `format: 'user'`).\n * Backed by the core autocomplete OCS endpoint, which is available to every\n * authenticated user (unlike the admin-only `cloud/users` provisioning API).\n *\n * Options are mapped to `{ id: <uid>, label: <display name> }` so the picker\n * stores the stable UID string while showing the human name.\n *\n * @module utils/userAutocomplete\n */\n\nimport axios from '@nextcloud/axios'\nimport { generateOcsUrl } from '@nextcloud/router'\n\n/**\n * Map one autocomplete suggestion to a picker option, keeping only user\n * results. The OCS payload uses `id` for the UID, `label` for the display\n * name and `source` (`users`) / `shareType` (`0`) to mark a user entry.\n *\n * @param {object} suggestion A single autocomplete suggestion object.\n * @return {{id: string, label: string, displayName: string, subline: string}|null} Option or null when it isn't a user.\n */\nfunction toUserOption(suggestion) {\n\tif (!suggestion || typeof suggestion !== 'object') {\n\t\treturn null\n\t}\n\tconst isUser = suggestion.source === 'users'\n\t\t|| suggestion.shareType === 0\n\t\t|| (suggestion.value && suggestion.value.shareType === 0)\n\tif (!isUser) {\n\t\treturn null\n\t}\n\tconst uid = suggestion.id\n\t\t|| (suggestion.value && suggestion.value.shareWith)\n\tif (uid === undefined || uid === null || uid === '') {\n\t\treturn null\n\t}\n\tconst name = suggestion.label || String(uid)\n\treturn {\n\t\tid: String(uid),\n\t\tlabel: name,\n\t\t// NcSelectUsers reads `displayName` specifically (label: \"displayName\"\n\t\t// on the underlying NcSelect, and NcListItemIcon's `name` prop).\n\t\tdisplayName: name,\n\t\tsubline: suggestion.subline || '',\n\t}\n}\n\n/**\n * Search Nextcloud users by name/UID via the core autocomplete OCS endpoint.\n *\n * Fails soft: any network/HTTP error resolves to an empty list (the caller —\n * CnFormDialog — degrades to a plain text input on repeated failure) and the\n * error is swallowed so the console isn't spammed during typing.\n *\n * @param {string} [query] The search term (empty loads an initial page).\n * @param {object} [options] Tuning options.\n * @param {number} [options.limit] Max results (default 25).\n * @return {Promise<Array<{id: string, label: string, subline: string}>>} Picker options.\n */\nexport async function searchNextcloudUsers(query = '', options = {}) {\n\tconst { limit = 25 } = options\n\ttry {\n\t\tconst url = generateOcsUrl('core/autocomplete/get')\n\t\tconst response = await axios.get(url, {\n\t\t\theaders: {\n\t\t\t\t'OCS-APIRequest': 'true',\n\t\t\t\tAccept: 'application/json',\n\t\t\t},\n\t\t\tparams: {\n\t\t\t\tsearch: query || '',\n\t\t\t\titemType: ' ',\n\t\t\t\titemId: ' ',\n\t\t\t\t'shareTypes[]': 0,\n\t\t\t\tlimit,\n\t\t\t},\n\t\t})\n\t\t// OCS envelope: { ocs: { data: [ ... ] } }; tolerate a bare array too.\n\t\tconst data = response\n\t\t\t&& response.data\n\t\t\t&& response.data.ocs\n\t\t\t&& response.data.ocs.data\n\t\tconst list = Array.isArray(data)\n\t\t\t? data\n\t\t\t: (Array.isArray(response && response.data) ? response.data : [])\n\t\treturn list\n\t\t\t.map(toUserOption)\n\t\t\t.filter((opt) => opt !== null)\n\t} catch {\n\t\treturn []\n\t}\n}\n\n/**\n * Resolve a single user UID to a `{ id, label }` option for edit-mode display.\n * Tries the autocomplete endpoint with the UID as the query and matches the\n * exact UID; falls back to `{ id: uid, label: uid }` so the select always\n * shows at least the stored UID even when the name can't be resolved.\n *\n * @param {string} uid The stored user UID.\n * @return {Promise<{id: string, label: string}>} The resolved option.\n */\nexport async function resolveNextcloudUser(uid) {\n\tconst fallback = { id: String(uid), label: String(uid) }\n\tif (uid === undefined || uid === null || uid === '') {\n\t\treturn fallback\n\t}\n\tconst results = await searchNextcloudUsers(String(uid))\n\tconst match = results.find((opt) => opt.id === String(uid))\n\treturn match || fallback\n}\n"],"names":["axios"],"mappings":"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"}
1
+ {"version":3,"file":"userAutocomplete.js","sources":["../../../src/utils/userAutocomplete.js"],"sourcesContent":["/**\n * Nextcloud user autocomplete helpers.\n *\n * Resolves real Nextcloud users for the schema-driven form's user-picker\n * (a property marked `referenceType: 'nextcloud-user'` or `format: 'user'`).\n * Backed by the core autocomplete OCS endpoint, which is available to every\n * authenticated user (unlike the admin-only `cloud/users` provisioning API).\n *\n * Options are mapped to `{ id: <uid>, label: <display name> }` so the picker\n * stores the stable UID string while showing the human name.\n *\n * @module utils/userAutocomplete\n */\n\nimport { getCurrentUser } from '@nextcloud/auth'\nimport axios from '@nextcloud/axios'\nimport { generateOcsUrl } from '@nextcloud/router'\n\n/**\n * The signed-in user as a picker option, or null when nobody is signed in.\n *\n * Core autocomplete never returns the person who searches (it is built for\n * sharing, and you do not share with yourself), so a picker backed by it\n * alone cannot assign a task to yourself.\n *\n * @spec openspec/changes/audit-round-lib-fixes/specs/schema-utilities/spec.md\n * @return {{id: string, label: string, displayName: string, subline: string}|null} The option.\n */\nfunction currentUserOption() {\n\tlet user\n\ttry {\n\t\tuser = getCurrentUser()\n\t} catch {\n\t\treturn null\n\t}\n\tif (!user || !user.uid) {\n\t\treturn null\n\t}\n\tconst name = user.displayName || String(user.uid)\n\treturn { id: String(user.uid), label: name, displayName: name, subline: '' }\n}\n\n/**\n * Whether the current-user option matches a search term (uid or display\n * name contains the term, ignoring case). An empty term matches.\n *\n * @param {object} option The current-user option.\n * @param {string} query The search term.\n * @return {boolean} True when it matches.\n */\nfunction matchesQuery(option, query) {\n\tconst q = String(query || '').trim().toLowerCase()\n\tif (q === '') {\n\t\treturn true\n\t}\n\treturn option.id.toLowerCase().includes(q) || option.label.toLowerCase().includes(q)\n}\n\n/**\n * Map one autocomplete suggestion to a picker option, keeping only user\n * results. The OCS payload uses `id` for the UID, `label` for the display\n * name and `source` (`users`) / `shareType` (`0`) to mark a user entry.\n *\n * @param {object} suggestion A single autocomplete suggestion object.\n * @return {{id: string, label: string, displayName: string, subline: string}|null} Option or null when it isn't a user.\n */\nfunction toUserOption(suggestion) {\n\tif (!suggestion || typeof suggestion !== 'object') {\n\t\treturn null\n\t}\n\tconst isUser = suggestion.source === 'users'\n\t\t|| suggestion.shareType === 0\n\t\t|| (suggestion.value && suggestion.value.shareType === 0)\n\tif (!isUser) {\n\t\treturn null\n\t}\n\tconst uid = suggestion.id\n\t\t|| (suggestion.value && suggestion.value.shareWith)\n\tif (uid === undefined || uid === null || uid === '') {\n\t\treturn null\n\t}\n\tconst name = suggestion.label || String(uid)\n\treturn {\n\t\tid: String(uid),\n\t\tlabel: name,\n\t\t// NcSelectUsers reads `displayName` specifically (label: \"displayName\"\n\t\t// on the underlying NcSelect, and NcListItemIcon's `name` prop).\n\t\tdisplayName: name,\n\t\tsubline: suggestion.subline || '',\n\t}\n}\n\n/**\n * Search Nextcloud users by name/UID via the core autocomplete OCS endpoint.\n *\n * Fails soft: any network/HTTP error resolves to an empty list (the caller —\n * CnFormDialog — degrades to a plain text input on repeated failure) and the\n * error is swallowed so the console isn't spammed during typing.\n *\n * @param {string} [query] The search term (empty loads an initial page).\n * @param {object} [options] Tuning options.\n * @param {number} [options.limit] Max results (default 25).\n * @param {boolean} [options.includeCurrentUser] Add the signed-in user when they match (default true; a mention list passes false).\n * @return {Promise<Array<{id: string, label: string, subline: string}>>} Picker options.\n */\nexport async function searchNextcloudUsers(query = '', options = {}) {\n\tconst { limit = 25, includeCurrentUser = true } = options\n\ttry {\n\t\tconst url = generateOcsUrl('core/autocomplete/get')\n\t\tconst response = await axios.get(url, {\n\t\t\theaders: {\n\t\t\t\t'OCS-APIRequest': 'true',\n\t\t\t\tAccept: 'application/json',\n\t\t\t},\n\t\t\tparams: {\n\t\t\t\tsearch: query || '',\n\t\t\t\titemType: ' ',\n\t\t\t\titemId: ' ',\n\t\t\t\t'shareTypes[]': 0,\n\t\t\t\tlimit,\n\t\t\t},\n\t\t})\n\t\t// OCS envelope: { ocs: { data: [ ... ] } }; tolerate a bare array too.\n\t\tconst data = response\n\t\t\t&& response.data\n\t\t\t&& response.data.ocs\n\t\t\t&& response.data.ocs.data\n\t\tconst list = Array.isArray(data)\n\t\t\t? data\n\t\t\t: (Array.isArray(response && response.data) ? response.data : [])\n\t\tconst found = list\n\t\t\t.map(toUserOption)\n\t\t\t.filter((opt) => opt !== null)\n\t\treturn includeCurrentUser ? withCurrentUser(found, query) : found\n\t} catch {\n\t\treturn []\n\t}\n}\n\n/**\n * Put the signed-in user first in a result list when they match the search\n * and the server left them out.\n *\n * @spec openspec/changes/audit-round-lib-fixes/specs/schema-utilities/spec.md\n * @param {Array<object>} options The server's options.\n * @param {string} query The search term.\n * @return {Array<object>} The options, the current user included when they match.\n */\nfunction withCurrentUser(options, query) {\n\tconst me = currentUserOption()\n\tif (!me || !matchesQuery(me, query) || options.some((opt) => opt.id === me.id)) {\n\t\treturn options\n\t}\n\treturn [me, ...options]\n}\n\n/**\n * Resolve a single user UID to a `{ id, label }` option for edit-mode display.\n * Tries the autocomplete endpoint with the UID as the query and matches the\n * exact UID; falls back to `{ id: uid, label: uid }` so the select always\n * shows at least the stored UID even when the name can't be resolved.\n *\n * @param {string} uid The stored user UID.\n * @return {Promise<{id: string, label: string}>} The resolved option.\n */\nexport async function resolveNextcloudUser(uid) {\n\tconst fallback = { id: String(uid), label: String(uid) }\n\tif (uid === undefined || uid === null || uid === '') {\n\t\treturn fallback\n\t}\n\t// The server never returns the signed-in user, so their own uid would\n\t// otherwise fall back to the bare uid.\n\tconst me = currentUserOption()\n\tif (me && me.id === String(uid)) {\n\t\treturn me\n\t}\n\tconst results = await searchNextcloudUsers(String(uid))\n\tconst match = results.find((opt) => opt.id === String(uid))\n\treturn match || fallback\n}\n"],"names":["axios"],"mappings":"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"}