@conduction/nextcloud-vue 0.1.0-beta.1 → 0.1.0-beta.11

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 (208) hide show
  1. package/README.md +226 -0
  2. package/css/index.css +5 -0
  3. package/dist/nextcloud-vue.cjs.js +79416 -7715
  4. package/dist/nextcloud-vue.cjs.js.map +1 -1
  5. package/dist/nextcloud-vue.css +3583 -504
  6. package/dist/nextcloud-vue.esm.js +79343 -7692
  7. package/dist/nextcloud-vue.esm.js.map +1 -1
  8. package/l10n/en.json +164 -0
  9. package/l10n/nl.json +164 -0
  10. package/package.json +104 -63
  11. package/src/components/CnActionsBar/CnActionsBar.vue +254 -0
  12. package/src/components/CnActionsBar/index.js +1 -0
  13. package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +570 -0
  14. package/src/components/CnAdvancedFormDialog/CnDataTab.vue +217 -0
  15. package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +121 -0
  16. package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +422 -0
  17. package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +247 -0
  18. package/src/components/CnAdvancedFormDialog/index.js +1 -0
  19. package/src/components/CnCard/CnCard.vue +415 -0
  20. package/src/components/CnCard/index.js +1 -0
  21. package/src/components/CnCardGrid/CnCardGrid.vue +156 -152
  22. package/src/components/CnCardGrid/index.js +1 -1
  23. package/src/components/CnCellRenderer/CnCellRenderer.vue +132 -132
  24. package/src/components/CnCellRenderer/index.js +1 -1
  25. package/src/components/CnChartWidget/CnChartWidget.vue +346 -0
  26. package/src/components/CnChartWidget/index.js +1 -0
  27. package/src/components/CnConfigurationCard/CnConfigurationCard.vue +77 -77
  28. package/src/components/CnConfigurationCard/index.js +1 -1
  29. package/src/components/CnContextMenu/CnContextMenu.vue +142 -0
  30. package/src/components/CnContextMenu/index.js +1 -0
  31. package/src/components/CnCopyDialog/CnCopyDialog.vue +266 -0
  32. package/src/components/CnCopyDialog/index.js +1 -0
  33. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +229 -0
  34. package/src/components/CnDashboardGrid/index.js +1 -0
  35. package/src/components/CnDashboardPage/CnDashboardPage.vue +397 -0
  36. package/src/components/CnDashboardPage/index.js +1 -0
  37. package/src/components/CnDataTable/CnDataTable.vue +362 -354
  38. package/src/components/CnDataTable/index.js +1 -1
  39. package/src/components/CnDeleteDialog/CnDeleteDialog.vue +177 -0
  40. package/src/components/CnDeleteDialog/index.js +1 -0
  41. package/src/components/CnDetailCard/CnDetailCard.vue +225 -0
  42. package/src/components/CnDetailCard/index.js +1 -0
  43. package/src/components/CnDetailGrid/CnDetailGrid.vue +256 -0
  44. package/src/components/CnDetailGrid/index.js +1 -0
  45. package/src/components/CnDetailPage/CnDetailPage.vue +432 -0
  46. package/src/components/CnDetailPage/index.js +1 -0
  47. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +234 -223
  48. package/src/components/CnFacetSidebar/index.js +1 -1
  49. package/src/components/CnFilterBar/CnFilterBar.vue +153 -152
  50. package/src/components/CnFilterBar/index.js +1 -1
  51. package/src/components/CnFormDialog/CnFormDialog.vue +1047 -0
  52. package/src/components/CnFormDialog/index.js +1 -0
  53. package/src/components/CnIcon/CnIcon.vue +89 -0
  54. package/src/components/CnIcon/index.js +1 -0
  55. package/src/components/CnIndexPage/CnIndexPage.vue +980 -682
  56. package/src/components/CnIndexPage/index.js +1 -1
  57. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +536 -0
  58. package/src/components/CnIndexSidebar/index.js +1 -0
  59. package/src/components/CnInfoWidget/CnInfoWidget.vue +219 -0
  60. package/src/components/CnInfoWidget/index.js +1 -0
  61. package/src/components/CnItemCard/CnItemCard.vue +134 -0
  62. package/src/components/CnItemCard/index.js +1 -0
  63. package/src/components/CnJsonViewer/CnJsonViewer.vue +312 -0
  64. package/src/components/CnJsonViewer/index.js +1 -0
  65. package/src/components/CnKpiGrid/CnKpiGrid.vue +93 -89
  66. package/src/components/CnKpiGrid/index.js +1 -1
  67. package/src/components/CnMassActionBar/CnMassActionBar.vue +161 -160
  68. package/src/components/CnMassActionBar/index.js +1 -1
  69. package/src/components/CnMassCopyDialog/CnMassCopyDialog.vue +327 -320
  70. package/src/components/CnMassCopyDialog/index.js +1 -1
  71. package/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue +245 -238
  72. package/src/components/CnMassDeleteDialog/index.js +1 -1
  73. package/src/components/CnMassExportDialog/CnMassExportDialog.vue +191 -190
  74. package/src/components/CnMassExportDialog/index.js +1 -1
  75. package/src/components/CnMassImportDialog/CnMassImportDialog.vue +494 -491
  76. package/src/components/CnMassImportDialog/index.js +1 -1
  77. package/src/components/CnNoteCard/CnNoteCard.vue +149 -0
  78. package/src/components/CnNoteCard/index.js +1 -0
  79. package/src/components/CnNotesCard/CnNotesCard.vue +416 -0
  80. package/src/components/CnNotesCard/index.js +1 -0
  81. package/src/components/CnObjectCard/CnObjectCard.vue +294 -292
  82. package/src/components/CnObjectCard/index.js +1 -1
  83. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +854 -0
  84. package/src/components/CnObjectDataWidget/index.js +1 -0
  85. package/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +289 -0
  86. package/src/components/CnObjectMetadataWidget/index.js +1 -0
  87. package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +369 -0
  88. package/src/components/CnObjectSidebar/CnFilesTab.vue +287 -0
  89. package/src/components/CnObjectSidebar/CnNotesTab.vue +250 -0
  90. package/src/components/CnObjectSidebar/CnObjectSidebar.vue +255 -0
  91. package/src/components/CnObjectSidebar/CnTagsTab.vue +259 -0
  92. package/src/components/CnObjectSidebar/CnTasksTab.vue +483 -0
  93. package/src/components/CnObjectSidebar/index.js +6 -0
  94. package/src/components/CnPageHeader/CnPageHeader.vue +61 -0
  95. package/src/components/CnPageHeader/index.js +1 -0
  96. package/src/components/CnPagination/CnPagination.vue +253 -252
  97. package/src/components/CnPagination/index.js +1 -1
  98. package/src/components/CnProgressBar/CnProgressBar.vue +262 -0
  99. package/src/components/CnProgressBar/index.js +1 -0
  100. package/src/components/CnRegisterMapping/CnRegisterMapping.vue +793 -0
  101. package/src/components/CnRegisterMapping/index.js +1 -0
  102. package/src/components/CnRowActions/CnRowActions.vue +95 -73
  103. package/src/components/CnRowActions/index.js +1 -1
  104. package/src/components/CnSchemaFormDialog/CnSchemaConfigurationTab.vue +226 -0
  105. package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +788 -0
  106. package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +305 -0
  107. package/src/components/CnSchemaFormDialog/CnSchemaPropertyActions.vue +1398 -0
  108. package/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue +236 -0
  109. package/src/components/CnSchemaFormDialog/index.js +1 -0
  110. package/src/components/CnSettingsCard/CnSettingsCard.vue +92 -92
  111. package/src/components/CnSettingsCard/index.js +1 -1
  112. package/src/components/CnSettingsSection/CnSettingsSection.vue +267 -266
  113. package/src/components/CnSettingsSection/index.js +1 -1
  114. package/src/components/CnStatsBlock/CnStatsBlock.vue +437 -366
  115. package/src/components/CnStatsBlock/index.js +1 -1
  116. package/src/components/CnStatsPanel/CnStatsPanel.vue +321 -0
  117. package/src/components/CnStatsPanel/index.js +1 -0
  118. package/src/components/CnStatusBadge/CnStatusBadge.vue +90 -77
  119. package/src/components/CnStatusBadge/index.js +1 -1
  120. package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +545 -0
  121. package/src/components/CnTabbedFormDialog/index.js +1 -0
  122. package/src/components/CnTableWidget/CnTableWidget.vue +333 -0
  123. package/src/components/CnTableWidget/index.js +1 -0
  124. package/src/components/CnTasksCard/CnTasksCard.vue +374 -0
  125. package/src/components/CnTasksCard/index.js +1 -0
  126. package/src/components/CnTileWidget/CnTileWidget.vue +159 -0
  127. package/src/components/CnTileWidget/index.js +1 -0
  128. package/src/components/CnTimelineStages/CnTimelineStages.vue +294 -0
  129. package/src/components/CnTimelineStages/index.js +1 -0
  130. package/src/components/CnUserActionMenu/CnUserActionMenu.vue +436 -0
  131. package/src/components/CnUserActionMenu/index.js +1 -0
  132. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +313 -312
  133. package/src/components/CnVersionInfoCard/index.js +1 -1
  134. package/src/components/CnWidgetRenderer/CnWidgetRenderer.vue +180 -0
  135. package/src/components/CnWidgetRenderer/index.js +1 -0
  136. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +248 -0
  137. package/src/components/CnWidgetWrapper/index.js +1 -0
  138. package/src/components/index.js +57 -25
  139. package/src/composables/index.js +5 -3
  140. package/src/composables/useContextMenu.js +126 -0
  141. package/src/composables/useDashboardView.js +286 -0
  142. package/src/composables/useDetailView.js +290 -132
  143. package/src/composables/useListView.js +364 -153
  144. package/src/composables/useSubResource.js +142 -142
  145. package/src/constants/metadata.js +30 -0
  146. package/src/css/CnSchemaFormDialog.css +546 -0
  147. package/src/css/__sample_nextcloud_tokens.css +110 -0
  148. package/src/css/actions-bar.css +54 -0
  149. package/src/css/badge.css +83 -51
  150. package/src/css/card.css +129 -128
  151. package/src/css/context-menu.css +20 -0
  152. package/src/css/dashboard.css +70 -0
  153. package/src/css/detail-page.css +235 -0
  154. package/src/css/detail.css +68 -68
  155. package/src/css/index-page.css +44 -0
  156. package/src/css/index-sidebar.css +193 -0
  157. package/src/css/index.css +17 -8
  158. package/src/css/layout.css +90 -90
  159. package/src/css/page-header.css +35 -0
  160. package/src/css/pagination.css +72 -72
  161. package/src/css/table.css +142 -143
  162. package/src/css/timeline-stages.css +220 -0
  163. package/src/css/utilities.css +46 -46
  164. package/src/index.js +95 -50
  165. package/src/l10n/index.js +12 -0
  166. package/src/mixins/gridLayout.js +118 -0
  167. package/src/store/createCrudStore.d.ts +350 -0
  168. package/src/store/createCrudStore.js +413 -0
  169. package/src/store/createSubResourcePlugin.js +125 -135
  170. package/src/store/index.js +4 -3
  171. package/src/store/pluginMerge.js +55 -0
  172. package/src/store/plugins/auditTrails.js +357 -17
  173. package/src/store/plugins/files.js +250 -186
  174. package/src/store/plugins/index.js +8 -4
  175. package/src/store/plugins/lifecycle.js +180 -180
  176. package/src/store/plugins/logs.d.ts +22 -0
  177. package/src/store/plugins/logs.js +172 -0
  178. package/src/store/plugins/registerMapping.js +195 -0
  179. package/src/store/plugins/relations.js +68 -68
  180. package/src/store/plugins/search.js +385 -0
  181. package/src/store/plugins/selection.js +104 -0
  182. package/src/store/useObjectStore.js +793 -625
  183. package/src/types/auditTrail.d.ts +32 -32
  184. package/src/types/file.d.ts +23 -23
  185. package/src/types/index.d.ts +67 -35
  186. package/src/types/notification.d.ts +36 -36
  187. package/src/types/object.d.ts +40 -40
  188. package/src/types/organisation.d.ts +41 -41
  189. package/src/types/register.d.ts +25 -25
  190. package/src/types/schema.d.ts +39 -39
  191. package/src/types/shared.d.ts +79 -79
  192. package/src/types/source.d.ts +14 -14
  193. package/src/types/task.d.ts +31 -31
  194. package/src/utils/errors.js +96 -96
  195. package/src/utils/getTheme.js +9 -0
  196. package/src/utils/headers.js +80 -44
  197. package/src/utils/id.js +13 -0
  198. package/src/utils/index.js +4 -3
  199. package/src/utils/schema.js +423 -287
  200. package/src/utils/widgetVisibility.js +162 -0
  201. package/src/components/CnDetailViewLayout/CnDetailViewLayout.vue +0 -88
  202. package/src/components/CnDetailViewLayout/index.js +0 -1
  203. package/src/components/CnEmptyState/CnEmptyState.vue +0 -78
  204. package/src/components/CnEmptyState/index.js +0 -1
  205. package/src/components/CnListViewLayout/CnListViewLayout.vue +0 -80
  206. package/src/components/CnListViewLayout/index.js +0 -1
  207. package/src/components/CnViewModeToggle/CnViewModeToggle.vue +0 -77
  208. package/src/components/CnViewModeToggle/index.js +0 -1
@@ -1,180 +1,180 @@
1
- import { buildHeaders } from '../../utils/headers.js'
2
- import { parseResponseError, networkError } from '../../utils/errors.js'
3
-
4
- /**
5
- * Lifecycle plugin for the object store.
6
- *
7
- * Adds object lifecycle actions: lock, unlock, publish, depublish, revert, merge.
8
- * These operate on the object itself (not sub-resources) but share the same
9
- * URL pattern: POST /{register}/{schema}/{objectId}/{action}
10
- *
11
- * State: lifecycleLoading, lifecycleError
12
- * Actions: lockObject, unlockObject, publishObject, depublishObject, revertObject, mergeObjects
13
- *
14
- * @return {Function} Plugin factory
15
- *
16
- * @example
17
- * const useStore = createObjectStore('object', {
18
- * plugins: [lifecyclePlugin()],
19
- * })
20
- * const store = useStore()
21
- * await store.lockObject('case', caseId, { process: 'review', duration: 3600 })
22
- * await store.publishObject('case', caseId, { date: '2025-01-01' })
23
- */
24
- export function lifecyclePlugin() {
25
- return {
26
- name: 'Lifecycle',
27
-
28
- state: () => ({
29
- lifecycleLoading: false,
30
- lifecycleError: null,
31
- }),
32
-
33
- getters: {
34
- isLifecycleLoading: (state) => state.lifecycleLoading,
35
- getLifecycleError: (state) => state.lifecycleError,
36
- },
37
-
38
- actions: {
39
- /**
40
- * Perform a lifecycle action on an object.
41
- *
42
- * @param {string} type The registered object type slug
43
- * @param {string} objectId The object ID
44
- * @param {string} action The lifecycle action endpoint (e.g. 'lock', 'publish')
45
- * @param {object} [body=null] Optional request body
46
- * @return {Promise<object|null>} Response data or null on error
47
- */
48
- async _lifecycleAction(type, objectId, action, body = null) {
49
- this.lifecycleLoading = true
50
- this.lifecycleError = null
51
-
52
- try {
53
- const url = this._buildUrl(type, objectId) + '/' + action
54
- const options = {
55
- method: 'POST',
56
- headers: buildHeaders(),
57
- }
58
- if (body) {
59
- options.body = JSON.stringify(body)
60
- }
61
-
62
- const response = await fetch(url, options)
63
-
64
- if (!response.ok) {
65
- this.lifecycleError = await parseResponseError(response, action)
66
- console.error(`Error performing ${action} on ${type}/${objectId}:`, this.lifecycleError)
67
- return null
68
- }
69
-
70
- const data = await response.json()
71
-
72
- if (this.objects[type] && data.id) {
73
- this.objects[type][data.id] = data
74
- }
75
-
76
- return data
77
- } catch (error) {
78
- this.lifecycleError = error.name === 'TypeError'
79
- ? networkError(error)
80
- : { status: null, message: error.message, details: null, isValidation: false, fields: null, toString() { return this.message } }
81
- console.error(`Error performing ${action} on ${type}/${objectId}:`, error)
82
- return null
83
- } finally {
84
- this.lifecycleLoading = false
85
- }
86
- },
87
-
88
- /**
89
- * Lock an object to prevent concurrent edits.
90
- *
91
- * @param {string} type The registered object type slug
92
- * @param {string} objectId The object ID
93
- * @param {object} options Lock options
94
- * @param {string} [options.process] Lock reason/process name
95
- * @param {number} [options.duration] Lock duration in seconds
96
- * @return {Promise<object|null>} Updated object or null on error
97
- */
98
- async lockObject(type, objectId, options = {}) {
99
- return this._lifecycleAction(type, objectId, 'lock', options)
100
- },
101
-
102
- /**
103
- * Unlock an object.
104
- *
105
- * @param {string} type The registered object type slug
106
- * @param {string} objectId The object ID
107
- * @return {Promise<object|null>} Updated object or null on error
108
- */
109
- async unlockObject(type, objectId) {
110
- return this._lifecycleAction(type, objectId, 'unlock')
111
- },
112
-
113
- /**
114
- * Publish an object (make it publicly accessible).
115
- *
116
- * @param {string} type The registered object type slug
117
- * @param {string} objectId The object ID
118
- * @param {object} [options={}] Publish options
119
- * @param {string} [options.date] Publish date (ISO 8601)
120
- * @return {Promise<object|null>} Updated object or null on error
121
- */
122
- async publishObject(type, objectId, options = {}) {
123
- return this._lifecycleAction(type, objectId, 'publish', options)
124
- },
125
-
126
- /**
127
- * Depublish an object (revoke public access).
128
- *
129
- * @param {string} type The registered object type slug
130
- * @param {string} objectId The object ID
131
- * @param {object} [options={}] Depublish options
132
- * @param {string} [options.date] Depublish date (ISO 8601)
133
- * @return {Promise<object|null>} Updated object or null on error
134
- */
135
- async depublishObject(type, objectId, options = {}) {
136
- return this._lifecycleAction(type, objectId, 'depublish', options)
137
- },
138
-
139
- /**
140
- * Revert an object to a previous version.
141
- *
142
- * @param {string} type The registered object type slug
143
- * @param {string} objectId The object ID
144
- * @param {object} options Revert options
145
- * @param {string} [options.datetime] Target datetime
146
- * @param {string} [options.auditTrailId] Audit trail entry ID to revert to
147
- * @param {number} [options.version] Target version number
148
- * @param {boolean} [options.overwriteVersion] Overwrite current version
149
- * @return {Promise<object|null>} Updated object or null on error
150
- */
151
- async revertObject(type, objectId, options = {}) {
152
- return this._lifecycleAction(type, objectId, 'revert', options)
153
- },
154
-
155
- /**
156
- * Merge two objects together.
157
- *
158
- * @param {string} type The registered object type slug
159
- * @param {string} sourceId The source object ID (will be merged into target)
160
- * @param {object} options Merge options
161
- * @param {string} options.target Target object ID
162
- * @param {string} [options.fileAction] How to handle files ('move'|'copy'|'skip')
163
- * @param {string} [options.relationAction] How to handle relations
164
- * @param {string} [options.referenceAction] How to handle references
165
- * @return {Promise<object|null>} Merge result or null on error
166
- */
167
- async mergeObjects(type, sourceId, options = {}) {
168
- return this._lifecycleAction(type, sourceId, 'merge', options)
169
- },
170
-
171
- /**
172
- * Clear lifecycle state.
173
- */
174
- clearLifecycle() {
175
- this.lifecycleLoading = false
176
- this.lifecycleError = null
177
- },
178
- },
179
- }
180
- }
1
+ import { buildHeaders } from '../../utils/headers.js'
2
+ import { parseResponseError, networkError } from '../../utils/errors.js'
3
+
4
+ /**
5
+ * Lifecycle plugin for the object store.
6
+ *
7
+ * Adds object lifecycle actions: lock, unlock, publish, depublish, revert, merge.
8
+ * These operate on the object itself (not sub-resources) but share the same
9
+ * URL pattern: POST /{register}/{schema}/{objectId}/{action}
10
+ *
11
+ * State: lifecycleLoading, lifecycleError
12
+ * Actions: lockObject, unlockObject, publishObject, depublishObject, revertObject, mergeObjects
13
+ *
14
+ * @return {Function} Plugin factory
15
+ *
16
+ * @example
17
+ * const useStore = createObjectStore('object', {
18
+ * plugins: [lifecyclePlugin()],
19
+ * })
20
+ * const store = useStore()
21
+ * await store.lockObject('case', caseId, { process: 'review', duration: 3600 })
22
+ * await store.publishObject('case', caseId, { date: '2025-01-01' })
23
+ */
24
+ export function lifecyclePlugin() {
25
+ return {
26
+ name: 'Lifecycle',
27
+
28
+ state: () => ({
29
+ lifecycleLoading: false,
30
+ lifecycleError: null,
31
+ }),
32
+
33
+ getters: {
34
+ isLifecycleLoading: (state) => state.lifecycleLoading,
35
+ getLifecycleError: (state) => state.lifecycleError,
36
+ },
37
+
38
+ actions: {
39
+ /**
40
+ * Perform a lifecycle action on an object.
41
+ *
42
+ * @param {string} type The registered object type slug
43
+ * @param {string} objectId The object ID
44
+ * @param {string} action The lifecycle action endpoint (e.g. 'lock', 'publish')
45
+ * @param {object} [body] Optional request body
46
+ * @return {Promise<object|null>} Response data or null on error
47
+ */
48
+ async _lifecycleAction(type, objectId, action, body = null) {
49
+ this.lifecycleLoading = true
50
+ this.lifecycleError = null
51
+
52
+ try {
53
+ const url = this._buildUrl(type, objectId) + '/' + action
54
+ const options = {
55
+ method: 'POST',
56
+ headers: buildHeaders(),
57
+ }
58
+ if (body) {
59
+ options.body = JSON.stringify(body)
60
+ }
61
+
62
+ const response = await fetch(url, options)
63
+
64
+ if (!response.ok) {
65
+ this.lifecycleError = await parseResponseError(response, action)
66
+ console.error(`Error performing ${action} on ${type}/${objectId}:`, this.lifecycleError)
67
+ return null
68
+ }
69
+
70
+ const data = await response.json()
71
+
72
+ if (this.objects[type] && data.id) {
73
+ this.objects = { ...this.objects, [type]: { ...this.objects[type], [data.id]: data } }
74
+ }
75
+
76
+ return data
77
+ } catch (error) {
78
+ this.lifecycleError = error.name === 'TypeError'
79
+ ? networkError(error)
80
+ : { status: null, message: error.message, details: null, isValidation: false, fields: null, toString() { return this.message } }
81
+ console.error(`Error performing ${action} on ${type}/${objectId}:`, error)
82
+ return null
83
+ } finally {
84
+ this.lifecycleLoading = false
85
+ }
86
+ },
87
+
88
+ /**
89
+ * Lock an object to prevent concurrent edits.
90
+ *
91
+ * @param {string} type The registered object type slug
92
+ * @param {string} objectId The object ID
93
+ * @param {object} options Lock options
94
+ * @param {string} [options.process] Lock reason/process name
95
+ * @param {number} [options.duration] Lock duration in seconds
96
+ * @return {Promise<object|null>} Updated object or null on error
97
+ */
98
+ async lockObject(type, objectId, options = {}) {
99
+ return this._lifecycleAction(type, objectId, 'lock', options)
100
+ },
101
+
102
+ /**
103
+ * Unlock an object.
104
+ *
105
+ * @param {string} type The registered object type slug
106
+ * @param {string} objectId The object ID
107
+ * @return {Promise<object|null>} Updated object or null on error
108
+ */
109
+ async unlockObject(type, objectId) {
110
+ return this._lifecycleAction(type, objectId, 'unlock')
111
+ },
112
+
113
+ /**
114
+ * Publish an object (make it publicly accessible).
115
+ *
116
+ * @param {string} type The registered object type slug
117
+ * @param {string} objectId The object ID
118
+ * @param {object} [options] Publish options
119
+ * @param {string} [options.date] Publish date (ISO 8601)
120
+ * @return {Promise<object|null>} Updated object or null on error
121
+ */
122
+ async publishObject(type, objectId, options = {}) {
123
+ return this._lifecycleAction(type, objectId, 'publish', options)
124
+ },
125
+
126
+ /**
127
+ * Depublish an object (revoke public access).
128
+ *
129
+ * @param {string} type The registered object type slug
130
+ * @param {string} objectId The object ID
131
+ * @param {object} [options] Depublish options
132
+ * @param {string} [options.date] Depublish date (ISO 8601)
133
+ * @return {Promise<object|null>} Updated object or null on error
134
+ */
135
+ async depublishObject(type, objectId, options = {}) {
136
+ return this._lifecycleAction(type, objectId, 'depublish', options)
137
+ },
138
+
139
+ /**
140
+ * Revert an object to a previous version.
141
+ *
142
+ * @param {string} type The registered object type slug
143
+ * @param {string} objectId The object ID
144
+ * @param {object} options Revert options
145
+ * @param {string} [options.datetime] Target datetime
146
+ * @param {string} [options.auditTrailId] Audit trail entry ID to revert to
147
+ * @param {number} [options.version] Target version number
148
+ * @param {boolean} [options.overwriteVersion] Overwrite current version
149
+ * @return {Promise<object|null>} Updated object or null on error
150
+ */
151
+ async revertObject(type, objectId, options = {}) {
152
+ return this._lifecycleAction(type, objectId, 'revert', options)
153
+ },
154
+
155
+ /**
156
+ * Merge two objects together.
157
+ *
158
+ * @param {string} type The registered object type slug
159
+ * @param {string} sourceId The source object ID (will be merged into target)
160
+ * @param {object} options Merge options
161
+ * @param {string} options.target Target object ID
162
+ * @param {string} [options.fileAction] How to handle files ('move'|'copy'|'skip')
163
+ * @param {string} [options.relationAction] How to handle relations
164
+ * @param {string} [options.referenceAction] How to handle references
165
+ * @return {Promise<object|null>} Merge result or null on error
166
+ */
167
+ async mergeObjects(type, sourceId, options = {}) {
168
+ return this._lifecycleAction(type, sourceId, 'merge', options)
169
+ },
170
+
171
+ /**
172
+ * Clear lifecycle state.
173
+ */
174
+ clearLifecycle() {
175
+ this.lifecycleLoading = false
176
+ this.lifecycleError = null
177
+ },
178
+ },
179
+ }
180
+ }
@@ -0,0 +1,22 @@
1
+ import type { CrudPlugin } from '../createCrudStore'
2
+
3
+ export interface LogsPluginOptions {
4
+ /** Required. Query-param name carrying the active item's id (e.g. 'source_id'). */
5
+ parentIdParam: string
6
+ /** Path segment appended to the store's base API URL. Default: 'logs'. */
7
+ path?: string
8
+ /** Default query params merged before caller-supplied filters. Default: `{ '_sort[created]': 'desc' }`. */
9
+ defaultSort?: Record<string, string>
10
+ /**
11
+ * When true, the plugin's `setup` hook registers a `store.$onAction`
12
+ * subscriber that auto-fires `refreshLogs()` after every `setItem` with
13
+ * an id (or `clearLogs()` when the item is cleared). Composes with other
14
+ * plugins that observe `setItem`.
15
+ */
16
+ autoRefreshOnItemChange?: boolean
17
+ }
18
+
19
+ /**
20
+ * Create a logs sub-resource plugin for a `createCrudStore`.
21
+ */
22
+ export function logsPlugin(options: LogsPluginOptions): CrudPlugin
@@ -0,0 +1,172 @@
1
+ import { buildHeaders, buildQueryString } from '../../utils/headers.js'
2
+ import { parseResponseError, networkError, genericError } from '../../utils/errors.js'
3
+
4
+ /**
5
+ * Logs sub-resource plugin for createCrudStore.
6
+ *
7
+ * Many apps expose a logs collection keyed off the parent resource ID, via a
8
+ * flat endpoint like `/sources/logs?source_id=<id>`. This plugin generates the
9
+ * standard state, getters, and actions for that pattern so consumer stores
10
+ * don't have to re-implement the same fetch/refresh logic.
11
+ *
12
+ * **Contributed state**
13
+ * - `logs` — last fetched response (raw array or `{ results, ... }` shape)
14
+ * - `logsLoading` — per-store loading flag
15
+ * - `logsError` — last error (`ApiError` or null)
16
+ *
17
+ * **Contributed getters**
18
+ * - `getLogs`, `isLogsLoading`, `getLogsError`
19
+ *
20
+ * **Contributed actions**
21
+ * - `refreshLogs(filters?)` — fetch and store; returns `{ response, data }`
22
+ * - `setLogs(data)` — replace state directly
23
+ * - `clearLogs()` — reset to empty
24
+ *
25
+ * When `autoRefreshOnItemChange: true`, the plugin registers a
26
+ * `store.$onAction` subscriber in its `setup` hook that observes `setItem`
27
+ * and triggers `refreshLogs()` / `clearLogs()` after the action resolves.
28
+ * This composes cleanly with other plugins that also want to observe
29
+ * `setItem` — none of them have to override the action.
30
+ *
31
+ * **URL construction**
32
+ * - `this._options.baseApiUrl + '/' + path` → e.g. `/sources/logs`
33
+ * - Query params: `{ [parentIdParam]: item.id, ...defaultSort, ...filters }` —
34
+ * caller-supplied filters always win.
35
+ *
36
+ * @param {object} options Plugin options
37
+ * @param {string} options.parentIdParam Required. Query param name carrying the
38
+ * parent resource's id — e.g. `'source_id'` for a sources store.
39
+ * @param {string} [options.path] Path segment appended to the store's base API
40
+ * URL. Default: `'logs'`.
41
+ * @param {object} [options.defaultSort] Default query params merged before
42
+ * user filters. Default: `{ '_sort[created]': 'desc' }`.
43
+ * @param {boolean} [options.autoRefreshOnItemChange] When true, overrides
44
+ * `setItem` so selecting a new item automatically refreshes logs. Default:
45
+ * `false`.
46
+ * @return {object} Plugin definition consumed by `createCrudStore`.
47
+ *
48
+ * @example
49
+ * import { createCrudStore, logsPlugin } from '@conduction/nextcloud-vue'
50
+ *
51
+ * export const useSourceStore = createCrudStore('source', {
52
+ * endpoint: 'sources',
53
+ * entity: Source,
54
+ * plugins: [logsPlugin({ parentIdParam: 'source_id', autoRefreshOnItemChange: true })],
55
+ * })
56
+ *
57
+ * // Later
58
+ * const store = useSourceStore()
59
+ * await store.refreshLogs({ '_limit': 50 })
60
+ * console.log(store.logs, store.logsLoading)
61
+ */
62
+ export function logsPlugin(options = {}) {
63
+ const {
64
+ parentIdParam,
65
+ path = 'logs',
66
+ defaultSort = { '_sort[created]': 'desc' },
67
+ autoRefreshOnItemChange = false,
68
+ } = options
69
+
70
+ if (!parentIdParam) {
71
+ throw new Error('logsPlugin: options.parentIdParam is required')
72
+ }
73
+
74
+ const actions = {
75
+ /**
76
+ * Fetch logs for the current item from the logs endpoint.
77
+ *
78
+ * @param {object} [filters] Extra query params (override defaults).
79
+ * @return {Promise<{ response: Response, data: unknown }>}
80
+ */
81
+ async refreshLogs(filters = {}) {
82
+ this.logsLoading = true
83
+ this.logsError = null
84
+
85
+ try {
86
+ const params = { ...defaultSort }
87
+ if (!(parentIdParam in filters) && this.item?.id != null) {
88
+ params[parentIdParam] = String(this.item.id)
89
+ }
90
+ Object.assign(params, filters)
91
+
92
+ const url = this._options.baseApiUrl + '/' + path + buildQueryString(params)
93
+ const response = await fetch(url, {
94
+ method: 'GET',
95
+ headers: buildHeaders(),
96
+ })
97
+
98
+ if (!response.ok) {
99
+ this.logsError = await parseResponseError(response, 'logs')
100
+ return { response, data: null }
101
+ }
102
+
103
+ const data = await response.json()
104
+ this.logs = data
105
+ return { response, data }
106
+ } catch (error) {
107
+ this.logsError = error?.name === 'TypeError'
108
+ ? networkError(error)
109
+ : genericError(error)
110
+ throw error
111
+ } finally {
112
+ this.logsLoading = false
113
+ }
114
+ },
115
+
116
+ /**
117
+ * Replace the logs state directly (e.g. when a parent action returned
118
+ * logs as a side effect).
119
+ *
120
+ * @param {unknown} data Response data (array or `{ results, ... }`).
121
+ */
122
+ setLogs(data) {
123
+ this.logs = data
124
+ },
125
+
126
+ /**
127
+ * Reset logs state back to empty defaults.
128
+ */
129
+ clearLogs() {
130
+ this.logs = []
131
+ this.logsLoading = false
132
+ this.logsError = null
133
+ },
134
+ }
135
+
136
+ const plugin = {
137
+ name: 'logs',
138
+
139
+ state: () => ({
140
+ logs: [],
141
+ logsLoading: false,
142
+ logsError: null,
143
+ }),
144
+
145
+ getters: {
146
+ getLogs: (state) => state.logs,
147
+ isLogsLoading: (state) => state.logsLoading,
148
+ getLogsError: (state) => state.logsError,
149
+ },
150
+
151
+ actions,
152
+ }
153
+
154
+ if (autoRefreshOnItemChange) {
155
+ plugin.setup = function setup(store) {
156
+ store.$onAction(({ name, after }) => {
157
+ if (name !== 'setItem') return
158
+ after(() => {
159
+ if (store.item?.id != null) {
160
+ store.refreshLogs().catch((error) => {
161
+ console.error('logsPlugin: auto-refresh failed:', error)
162
+ })
163
+ } else {
164
+ store.clearLogs()
165
+ }
166
+ })
167
+ })
168
+ }
169
+ }
170
+
171
+ return plugin
172
+ }