@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
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Shared helpers for merging Pinia store plugins into a store definition.
3
+ *
4
+ * Used by both `createObjectStore` (via `useObjectStore.js`) and
5
+ * `createCrudStore`, so plugin authors get the same shape everywhere:
6
+ * `{ name, state?, getters?, actions? }`.
7
+ */
8
+
9
+ /**
10
+ * Merge plugin state factories into a single state object.
11
+ *
12
+ * @param {Array} plugins Array of plugin definitions
13
+ * @return {object} Merged state object
14
+ */
15
+ export function mergePluginState(plugins) {
16
+ const merged = {}
17
+ for (const plugin of plugins) {
18
+ if (plugin.state) {
19
+ Object.assign(merged, plugin.state())
20
+ }
21
+ }
22
+ return merged
23
+ }
24
+
25
+ /**
26
+ * Merge plugin getters into a single getters object.
27
+ *
28
+ * @param {Array} plugins Array of plugin definitions
29
+ * @return {object} Merged getters object
30
+ */
31
+ export function mergePluginGetters(plugins) {
32
+ const merged = {}
33
+ for (const plugin of plugins) {
34
+ if (plugin.getters) {
35
+ Object.assign(merged, plugin.getters)
36
+ }
37
+ }
38
+ return merged
39
+ }
40
+
41
+ /**
42
+ * Merge plugin actions into a single actions object.
43
+ *
44
+ * @param {Array} plugins Array of plugin definitions
45
+ * @return {object} Merged actions object
46
+ */
47
+ export function mergePluginActions(plugins) {
48
+ const merged = {}
49
+ for (const plugin of plugins) {
50
+ if (plugin.actions) {
51
+ Object.assign(merged, plugin.actions)
52
+ }
53
+ }
54
+ return merged
55
+ }
@@ -1,17 +1,357 @@
1
- import { createSubResourcePlugin } from '../createSubResourcePlugin.js'
2
-
3
- /**
4
- * Audit trails plugin for the object store.
5
- *
6
- * Adds state, getters, and actions for fetching audit trail records
7
- * for an object. Read-only — no create/update/delete.
8
- *
9
- * State: auditTrails, auditTrailsLoading, auditTrailsError
10
- * Actions: fetchAuditTrails(type, objectId, params), clearAuditTrails()
11
- * Getters: getAuditTrails, isAuditTrailsLoading, getAuditTrailsError
12
- *
13
- * @param {object} [options={}] Plugin options
14
- * @param {number} [options.limit=20] Default page size
15
- * @return {Function} Plugin factory
16
- */
17
- export const auditTrailsPlugin = createSubResourcePlugin('auditTrails', 'audit-trails')
1
+ import { createSubResourcePlugin, emptyPaginated } from '../createSubResourcePlugin.js'
2
+ import { buildHeaders, buildQueryString } from '../../utils/headers.js'
3
+ import { parseResponseError, networkError, genericError } from '../../utils/errors.js'
4
+
5
+ /**
6
+ * Audit trails plugin for the object store.
7
+ *
8
+ * Extends the generic sub-resource plugin with global audit trail operations:
9
+ * fetching all audit trails (not scoped to one object), statistics, and delete.
10
+ *
11
+ * **Object-scoped** (from createSubResourcePlugin):
12
+ * State: auditTrails, auditTrailsLoading, auditTrailsError
13
+ * Actions: fetchAuditTrails(type, objectId, params), clearAuditTrails()
14
+ * Getters: getAuditTrails, isAuditTrailsLoading, getAuditTrailsError
15
+ *
16
+ * **Global** (added by this plugin):
17
+ * State: globalAuditTrails, globalAuditTrailsLoading, globalAuditTrailsError,
18
+ * auditTrailStatistics, auditTrailStatisticsLoading, auditTrailStatisticsError,
19
+ * auditTrailItem, auditTrailFilters, auditTrailSearch
20
+ * Actions: fetchGlobalAuditTrails(params), fetchAuditTrailStatistics(),
21
+ * deleteGlobalAuditTrail(id), deleteMultipleGlobalAuditTrails(ids),
22
+ * refreshGlobalAuditTrails(), setAuditTrailItem(item),
23
+ * setAuditTrailFilters(filters), setAuditTrailSearch(search),
24
+ * clearAuditTrailFilters(), clearGlobalAuditTrails()
25
+ * Getters: getGlobalAuditTrails, isGlobalAuditTrailsLoading, getGlobalAuditTrailsError,
26
+ * getAuditTrailStatistics, isAuditTrailStatisticsLoading, getAuditTrailStatisticsError,
27
+ * getAuditTrailItem, getAuditTrailFilters, getAuditTrailSearch
28
+ *
29
+ * @param {object} [options={}] Plugin options
30
+ * @param {number} [options.limit=20] Default page size for object-scoped queries
31
+ * @param {number} [options.globalLimit=50] Default page size for global queries
32
+ * @return {object} Plugin definition
33
+ *
34
+ * @example
35
+ * const useStore = createObjectStore('object', {
36
+ * plugins: [auditTrailsPlugin()],
37
+ * })
38
+ * const store = useStore()
39
+ *
40
+ * // Object-scoped (unchanged)
41
+ * await store.fetchAuditTrails('case', caseId)
42
+ *
43
+ * // Global
44
+ * await store.fetchGlobalAuditTrails({ _limit: 50, _page: 1 })
45
+ * await store.fetchAuditTrailStatistics()
46
+ * await store.deleteGlobalAuditTrail(id)
47
+ */
48
+
49
+ const GLOBAL_PATH = '/audit-trails'
50
+
51
+ const EMPTY_STATISTICS = {
52
+ total: 0,
53
+ create: 0,
54
+ update: 0,
55
+ delete: 0,
56
+ read: 0,
57
+ }
58
+
59
+ /**
60
+ * Build the global audit trails API URL from the store base URL.
61
+ * e.g. /apps/openregister/api/objects -> /apps/openregister/api/audit-trails
62
+ *
63
+ * @param {string} baseUrl Store base URL
64
+ * @return {string} Global audit trails endpoint URL
65
+ */
66
+ function buildGlobalUrl(baseUrl) {
67
+ return baseUrl.replace(/\/objects\/?$/, '') + GLOBAL_PATH
68
+ }
69
+
70
+ export function auditTrailsPlugin(options = {}) {
71
+ const base = createSubResourcePlugin('auditTrails', 'audit-trails', options)()
72
+ const globalLimit = options.globalLimit || 50
73
+
74
+ return {
75
+ ...base,
76
+
77
+ state: () => ({
78
+ ...base.state(),
79
+ globalAuditTrails: emptyPaginated(globalLimit),
80
+ globalAuditTrailsLoading: false,
81
+ globalAuditTrailsError: null,
82
+ auditTrailStatistics: { ...EMPTY_STATISTICS },
83
+ auditTrailStatisticsLoading: false,
84
+ auditTrailStatisticsError: null,
85
+ auditTrailItem: null,
86
+ auditTrailFilters: {},
87
+ auditTrailSearch: '',
88
+ }),
89
+
90
+ getters: {
91
+ ...base.getters,
92
+ getGlobalAuditTrails: (state) => state.globalAuditTrails,
93
+ isGlobalAuditTrailsLoading: (state) => state.globalAuditTrailsLoading || false,
94
+ getGlobalAuditTrailsError: (state) => state.globalAuditTrailsError || null,
95
+ getAuditTrailStatistics: (state) => state.auditTrailStatistics,
96
+ isAuditTrailStatisticsLoading: (state) => state.auditTrailStatisticsLoading || false,
97
+ getAuditTrailStatisticsError: (state) => state.auditTrailStatisticsError || null,
98
+ getAuditTrailItem: (state) => state.auditTrailItem || null,
99
+ getAuditTrailFilters: (state) => state.auditTrailFilters || {},
100
+ getAuditTrailSearch: (state) => state.auditTrailSearch || '',
101
+ },
102
+
103
+ actions: {
104
+ ...base.actions,
105
+
106
+ /**
107
+ * Fetch audit trails from the global endpoint (not scoped to an object).
108
+ *
109
+ * @param {object} [params] Query parameters (_limit, _page, _search, _order, filters)
110
+ * @return {Promise<Array>} The fetched results
111
+ */
112
+ async fetchGlobalAuditTrails(params = {}) {
113
+ this.globalAuditTrailsLoading = true
114
+ this.globalAuditTrailsError = null
115
+
116
+ try {
117
+ const url = buildGlobalUrl(this._options.baseUrl) + buildQueryString(params)
118
+
119
+ const response = await fetch(url, {
120
+ method: 'GET',
121
+ headers: buildHeaders(),
122
+ })
123
+
124
+ if (!response.ok) {
125
+ this.globalAuditTrailsError = await parseResponseError(response, 'audit trails')
126
+ console.error('Error fetching global audit trails:', this.globalAuditTrailsError)
127
+ return []
128
+ }
129
+
130
+ const data = await response.json()
131
+ const results = data.results || data
132
+
133
+ this.globalAuditTrails = {
134
+ results,
135
+ total: data.total || results.length,
136
+ page: data.page || 1,
137
+ pages: data.pages || 0,
138
+ limit: params._limit || globalLimit,
139
+ offset: data.offset || 0,
140
+ }
141
+
142
+ return results
143
+ } catch (error) {
144
+ this.globalAuditTrailsError = error.name === 'TypeError'
145
+ ? networkError(error)
146
+ : genericError(error)
147
+ console.error('Error fetching global audit trails:', error)
148
+ return []
149
+ } finally {
150
+ this.globalAuditTrailsLoading = false
151
+ }
152
+ },
153
+
154
+ /**
155
+ * Fetch audit trail statistics from the global statistics endpoint.
156
+ *
157
+ * @return {Promise<object>} The statistics object
158
+ */
159
+ async fetchAuditTrailStatistics() {
160
+ this.auditTrailStatisticsLoading = true
161
+ this.auditTrailStatisticsError = null
162
+
163
+ try {
164
+ const url = buildGlobalUrl(this._options.baseUrl) + '/statistics'
165
+
166
+ const response = await fetch(url, {
167
+ method: 'GET',
168
+ headers: buildHeaders(),
169
+ })
170
+
171
+ if (!response.ok) {
172
+ this.auditTrailStatisticsError = await parseResponseError(response, 'audit trail statistics')
173
+ console.error('Error fetching audit trail statistics:', this.auditTrailStatisticsError)
174
+ return { ...EMPTY_STATISTICS }
175
+ }
176
+
177
+ const data = await response.json()
178
+ this.auditTrailStatistics = { ...EMPTY_STATISTICS, ...data }
179
+ return this.auditTrailStatistics
180
+ } catch (error) {
181
+ this.auditTrailStatisticsError = error.name === 'TypeError'
182
+ ? networkError(error)
183
+ : genericError(error)
184
+ console.error('Error fetching audit trail statistics:', error)
185
+ return { ...EMPTY_STATISTICS }
186
+ } finally {
187
+ this.auditTrailStatisticsLoading = false
188
+ }
189
+ },
190
+
191
+ /**
192
+ * Delete a single audit trail by ID.
193
+ *
194
+ * @param {string} id The audit trail ID
195
+ * @return {Promise<boolean>} True if deleted successfully
196
+ */
197
+ async deleteGlobalAuditTrail(id) {
198
+ this.globalAuditTrailsLoading = true
199
+ this.globalAuditTrailsError = null
200
+
201
+ try {
202
+ const url = buildGlobalUrl(this._options.baseUrl) + `/${id}`
203
+
204
+ const response = await fetch(url, {
205
+ method: 'DELETE',
206
+ headers: buildHeaders(),
207
+ })
208
+
209
+ if (!response.ok) {
210
+ this.globalAuditTrailsError = await parseResponseError(response, 'audit trail')
211
+ console.error(`Error deleting audit trail ${id}:`, this.globalAuditTrailsError)
212
+ return false
213
+ }
214
+
215
+ this.globalAuditTrails = {
216
+ ...this.globalAuditTrails,
217
+ results: this.globalAuditTrails.results.filter((item) => item.id !== id),
218
+ total: Math.max(0, this.globalAuditTrails.total - 1),
219
+ }
220
+
221
+ return true
222
+ } catch (error) {
223
+ this.globalAuditTrailsError = error.name === 'TypeError'
224
+ ? networkError(error)
225
+ : genericError(error)
226
+ console.error(`Error deleting audit trail ${id}:`, error)
227
+ return false
228
+ } finally {
229
+ this.globalAuditTrailsLoading = false
230
+ }
231
+ },
232
+
233
+ /**
234
+ * Delete multiple audit trails by IDs.
235
+ *
236
+ * @param {string[]} ids Array of audit trail IDs to delete
237
+ * @return {Promise<boolean>} True if deleted successfully
238
+ */
239
+ async deleteMultipleGlobalAuditTrails(ids) {
240
+ if (!ids?.length) return true
241
+
242
+ this.globalAuditTrailsLoading = true
243
+ this.globalAuditTrailsError = null
244
+
245
+ try {
246
+ const url = buildGlobalUrl(this._options.baseUrl)
247
+
248
+ const response = await fetch(url, {
249
+ method: 'DELETE',
250
+ headers: buildHeaders(),
251
+ body: JSON.stringify({ ids }),
252
+ })
253
+
254
+ if (!response.ok) {
255
+ this.globalAuditTrailsError = await parseResponseError(response, 'audit trails')
256
+ console.error('Error deleting audit trails:', this.globalAuditTrailsError)
257
+ return false
258
+ }
259
+
260
+ const idSet = new Set(ids)
261
+ const remaining = this.globalAuditTrails.results.filter((item) => !idSet.has(item.id))
262
+
263
+ this.globalAuditTrails = {
264
+ ...this.globalAuditTrails,
265
+ results: remaining,
266
+ total: Math.max(0, this.globalAuditTrails.total - (this.globalAuditTrails.results.length - remaining.length)),
267
+ }
268
+
269
+ return true
270
+ } catch (error) {
271
+ this.globalAuditTrailsError = error.name === 'TypeError'
272
+ ? networkError(error)
273
+ : genericError(error)
274
+ console.error('Error deleting audit trails:', error)
275
+ return false
276
+ } finally {
277
+ this.globalAuditTrailsLoading = false
278
+ }
279
+ },
280
+
281
+ /**
282
+ * Re-fetch global audit trails with current pagination state.
283
+ *
284
+ * @return {Promise<Array>} The fetched results
285
+ */
286
+ async refreshGlobalAuditTrails() {
287
+ return this.fetchGlobalAuditTrails({
288
+ _limit: this.globalAuditTrails.limit,
289
+ _page: this.globalAuditTrails.page,
290
+ })
291
+ },
292
+
293
+ /**
294
+ * Set the active audit trail item (for detail views).
295
+ *
296
+ * @param {object|null} item The audit trail item or null to clear
297
+ */
298
+ setAuditTrailItem(item) {
299
+ this.auditTrailItem = item || null
300
+ },
301
+
302
+ /**
303
+ * Set audit trail filters (merged with existing).
304
+ *
305
+ * @param {object} filters Filter key-value pairs
306
+ */
307
+ setAuditTrailFilters(filters) {
308
+ this.auditTrailFilters = { ...this.auditTrailFilters, ...filters }
309
+ },
310
+
311
+ /**
312
+ * Set the audit trail search term.
313
+ *
314
+ * @param {string} search The search term
315
+ */
316
+ setAuditTrailSearch(search) {
317
+ this.auditTrailSearch = search || ''
318
+ },
319
+
320
+ /**
321
+ * Clear all audit trail filters and search.
322
+ */
323
+ clearAuditTrailFilters() {
324
+ this.auditTrailFilters = {}
325
+ this.auditTrailSearch = ''
326
+ },
327
+
328
+ /**
329
+ * Clear all global audit trail state back to defaults.
330
+ */
331
+ clearGlobalAuditTrails() {
332
+ this.globalAuditTrails = emptyPaginated(globalLimit)
333
+ this.globalAuditTrailsLoading = false
334
+ this.globalAuditTrailsError = null
335
+ this.auditTrailStatistics = { ...EMPTY_STATISTICS }
336
+ this.auditTrailStatisticsLoading = false
337
+ this.auditTrailStatisticsError = null
338
+ this.auditTrailItem = null
339
+ this.auditTrailFilters = {}
340
+ this.auditTrailSearch = ''
341
+ },
342
+
343
+ /**
344
+ * Clear all audit trail state (both object-scoped and global).
345
+ * Overrides the base clearAuditTrails so clearAllSubResources() clears everything.
346
+ */
347
+ clearAuditTrails() {
348
+ // Base sub-resource clear
349
+ this.auditTrails = emptyPaginated(options.limit || 20)
350
+ this.auditTrailsLoading = false
351
+ this.auditTrailsError = null
352
+ // Global clear
353
+ this.clearGlobalAuditTrails()
354
+ },
355
+ },
356
+ }
357
+ }