@conduction/nextcloud-vue 0.1.0-beta.6 → 0.1.0-beta.7
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.
- package/dist/nextcloud-vue.cjs.js +13606 -1918
- package/dist/nextcloud-vue.cjs.js.map +1 -1
- package/dist/nextcloud-vue.css +1238 -270
- package/dist/nextcloud-vue.esm.js +13548 -1880
- package/dist/nextcloud-vue.esm.js.map +1 -1
- package/package.json +9 -4
- package/src/components/CnActionsBar/CnActionsBar.vue +6 -1
- package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +1 -11
- package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +5 -1
- package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +1 -1
- package/src/components/CnCard/CnCard.vue +415 -0
- package/src/components/CnCard/index.js +1 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +20 -20
- package/src/components/CnChartWidget/CnChartWidget.vue +3 -1
- package/src/components/CnCopyDialog/CnCopyDialog.vue +7 -1
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +4 -0
- package/src/components/CnDashboardPage/CnDashboardPage.vue +2 -0
- package/src/components/CnDataTable/CnDataTable.vue +6 -2
- package/src/components/CnDeleteDialog/CnDeleteDialog.vue +7 -1
- package/src/components/CnDetailCard/CnDetailCard.vue +12 -1
- package/src/components/CnDetailGrid/CnDetailGrid.vue +254 -0
- package/src/components/CnDetailGrid/index.js +1 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +157 -11
- package/src/components/CnFacetSidebar/CnFacetSidebar.vue +3 -1
- package/src/components/CnFormDialog/CnFormDialog.vue +934 -920
- package/src/components/CnIcon/CnIcon.vue +1 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +51 -9
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +37 -9
- package/src/components/CnInfoWidget/CnInfoWidget.vue +219 -0
- package/src/components/CnInfoWidget/index.js +1 -0
- package/src/components/CnJsonViewer/CnJsonViewer.vue +283 -0
- package/src/components/CnJsonViewer/index.js +1 -0
- package/src/components/CnKpiGrid/CnKpiGrid.vue +5 -1
- package/src/components/CnMassCopyDialog/CnMassCopyDialog.vue +7 -1
- package/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue +7 -1
- package/src/components/CnMassExportDialog/CnMassExportDialog.vue +1 -1
- package/src/components/CnMassImportDialog/CnMassImportDialog.vue +1 -1
- package/src/components/CnObjectCard/CnObjectCard.vue +1 -1
- package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +368 -0
- package/src/components/CnObjectSidebar/CnFilesTab.vue +286 -0
- package/src/components/CnObjectSidebar/CnNotesTab.vue +249 -0
- package/src/components/CnObjectSidebar/CnObjectSidebar.vue +45 -668
- package/src/components/CnObjectSidebar/CnTagsTab.vue +258 -0
- package/src/components/CnObjectSidebar/CnTasksTab.vue +482 -0
- package/src/components/CnObjectSidebar/index.js +5 -0
- package/src/components/CnProgressBar/CnProgressBar.vue +262 -0
- package/src/components/CnProgressBar/index.js +1 -0
- package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +1 -1
- package/src/components/CnStatsBlock/CnStatsBlock.vue +27 -11
- package/src/components/CnStatsPanel/CnStatsPanel.vue +320 -0
- package/src/components/CnStatsPanel/index.js +1 -0
- package/src/components/CnStatusBadge/CnStatusBadge.vue +15 -2
- package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +5 -1
- package/src/components/CnTableWidget/CnTableWidget.vue +332 -0
- package/src/components/CnTableWidget/index.js +1 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +36 -1
- package/src/components/index.js +11 -0
- package/src/composables/useDashboardView.js +58 -12
- package/src/composables/useDetailView.js +3 -2
- package/src/composables/useListView.js +7 -6
- package/src/composables/useSubResource.js +3 -3
- package/src/css/badge.css +32 -0
- package/src/css/card.css +1 -0
- package/src/css/detail-page.css +74 -7
- package/src/index.js +16 -0
- package/src/mixins/gridLayout.js +118 -0
- package/src/store/createCrudStore.js +360 -0
- package/src/store/createSubResourcePlugin.js +5 -15
- package/src/store/index.js +1 -0
- package/src/store/plugins/auditTrails.js +346 -6
- package/src/store/plugins/lifecycle.js +4 -4
- package/src/store/plugins/registerMapping.js +18 -8
- package/src/store/plugins/relations.js +1 -1
- package/src/store/plugins/search.js +21 -8
- package/src/store/useObjectStore.js +30 -36
- package/src/utils/getTheme.js +9 -0
- package/src/utils/headers.js +13 -3
- package/src/utils/index.js +1 -0
- package/src/utils/schema.js +3 -3
- package/src/utils/widgetVisibility.js +162 -0
- package/src/components/CnObjectCard/eslint-setup.md +0 -235
- package/src/components/CnObjectCard/package.json-or.json +0 -132
|
@@ -1,17 +1,357 @@
|
|
|
1
|
-
import { createSubResourcePlugin } from '../createSubResourcePlugin.js'
|
|
1
|
+
import { createSubResourcePlugin, emptyPaginated } from '../createSubResourcePlugin.js'
|
|
2
|
+
import { buildHeaders, buildQueryString } from '../../utils/headers.js'
|
|
3
|
+
import { parseResponseError, networkError, genericError } from '../../utils/errors.js'
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Audit trails plugin for the object store.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
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.
|
|
8
10
|
*
|
|
11
|
+
* **Object-scoped** (from createSubResourcePlugin):
|
|
9
12
|
* State: auditTrails, auditTrailsLoading, auditTrailsError
|
|
10
13
|
* Actions: fetchAuditTrails(type, objectId, params), clearAuditTrails()
|
|
11
14
|
* Getters: getAuditTrails, isAuditTrailsLoading, getAuditTrailsError
|
|
12
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
|
+
*
|
|
13
29
|
* @param {object} [options={}] Plugin options
|
|
14
|
-
* @param {number} [options.limit=20] Default page size
|
|
15
|
-
* @
|
|
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
|
|
16
65
|
*/
|
|
17
|
-
|
|
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
|
+
}
|
|
@@ -42,7 +42,7 @@ export function lifecyclePlugin() {
|
|
|
42
42
|
* @param {string} type The registered object type slug
|
|
43
43
|
* @param {string} objectId The object ID
|
|
44
44
|
* @param {string} action The lifecycle action endpoint (e.g. 'lock', 'publish')
|
|
45
|
-
* @param {object} [body
|
|
45
|
+
* @param {object} [body] Optional request body
|
|
46
46
|
* @return {Promise<object|null>} Response data or null on error
|
|
47
47
|
*/
|
|
48
48
|
async _lifecycleAction(type, objectId, action, body = null) {
|
|
@@ -70,7 +70,7 @@ export function lifecyclePlugin() {
|
|
|
70
70
|
const data = await response.json()
|
|
71
71
|
|
|
72
72
|
if (this.objects[type] && data.id) {
|
|
73
|
-
this.objects[type][data.id]
|
|
73
|
+
this.objects = { ...this.objects, [type]: { ...this.objects[type], [data.id]: data } }
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
return data
|
|
@@ -115,7 +115,7 @@ export function lifecyclePlugin() {
|
|
|
115
115
|
*
|
|
116
116
|
* @param {string} type The registered object type slug
|
|
117
117
|
* @param {string} objectId The object ID
|
|
118
|
-
* @param {object} [options
|
|
118
|
+
* @param {object} [options] Publish options
|
|
119
119
|
* @param {string} [options.date] Publish date (ISO 8601)
|
|
120
120
|
* @return {Promise<object|null>} Updated object or null on error
|
|
121
121
|
*/
|
|
@@ -128,7 +128,7 @@ export function lifecyclePlugin() {
|
|
|
128
128
|
*
|
|
129
129
|
* @param {string} type The registered object type slug
|
|
130
130
|
* @param {string} objectId The object ID
|
|
131
|
-
* @param {object} [options
|
|
131
|
+
* @param {object} [options] Depublish options
|
|
132
132
|
* @param {string} [options.date] Depublish date (ISO 8601)
|
|
133
133
|
* @return {Promise<object|null>} Updated object or null on error
|
|
134
134
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildHeaders } from '../../utils/headers.js'
|
|
1
|
+
import { buildHeaders, prefixUrl } from '../../utils/headers.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Register mapping plugin for the object store.
|
|
@@ -28,7 +28,7 @@ export function registerMappingPlugin() {
|
|
|
28
28
|
state: () => ({
|
|
29
29
|
/** @type {Array} All available registers from OpenRegister */
|
|
30
30
|
registers: [],
|
|
31
|
-
/** @type {
|
|
31
|
+
/** @type {{[key: string]: Array}} Schemas keyed by register ID */
|
|
32
32
|
registerSchemas: {},
|
|
33
33
|
/** @type {boolean} Whether registers are being fetched */
|
|
34
34
|
registersLoading: false,
|
|
@@ -37,18 +37,28 @@ export function registerMappingPlugin() {
|
|
|
37
37
|
}),
|
|
38
38
|
|
|
39
39
|
getters: {
|
|
40
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* @param {object} state - Pinia state
|
|
42
|
+
* @return {Array} Raw register list
|
|
43
|
+
*/
|
|
41
44
|
getRegisters: (state) => state.registers,
|
|
42
45
|
|
|
43
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* @param {object} state - Pinia state
|
|
48
|
+
* @return {boolean} Whether registers are loading
|
|
49
|
+
*/
|
|
44
50
|
isRegistersLoading: (state) => state.registersLoading,
|
|
45
51
|
|
|
46
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* @param {object} state - Pinia state
|
|
54
|
+
* @return {string|null} Last error
|
|
55
|
+
*/
|
|
47
56
|
getRegistersError: (state) => state.registersError,
|
|
48
57
|
|
|
49
58
|
/**
|
|
50
59
|
* Registers as NcSelect-compatible options.
|
|
51
60
|
*
|
|
61
|
+
* @param {object} state - Pinia state
|
|
52
62
|
* @return {Array<{label: string, value: string}>}
|
|
53
63
|
*/
|
|
54
64
|
registerOptions: (state) => state.registers.map((r) => ({
|
|
@@ -75,7 +85,7 @@ export function registerMappingPlugin() {
|
|
|
75
85
|
/**
|
|
76
86
|
* Fetch all registers from OpenRegister with expanded schemas.
|
|
77
87
|
*
|
|
78
|
-
* @param {boolean} [withSchemas
|
|
88
|
+
* @param {boolean} [withSchemas] Include schemas in response
|
|
79
89
|
* @return {Promise<Array>} Fetched registers
|
|
80
90
|
*/
|
|
81
91
|
async fetchRegisters(withSchemas = true) {
|
|
@@ -83,7 +93,7 @@ export function registerMappingPlugin() {
|
|
|
83
93
|
this.registersError = null
|
|
84
94
|
|
|
85
95
|
try {
|
|
86
|
-
let url = '/apps/openregister/api/registers'
|
|
96
|
+
let url = prefixUrl('/apps/openregister/api/registers')
|
|
87
97
|
if (withSchemas) {
|
|
88
98
|
url += '?_extend[]=schemas'
|
|
89
99
|
}
|
|
@@ -155,7 +165,7 @@ export function registerMappingPlugin() {
|
|
|
155
165
|
// Fetch from API as fallback
|
|
156
166
|
try {
|
|
157
167
|
const response = await fetch(
|
|
158
|
-
`/apps/openregister/api/registers/${id}?_extend[]=schemas
|
|
168
|
+
prefixUrl(`/apps/openregister/api/registers/${id}?_extend[]=schemas`),
|
|
159
169
|
{ method: 'GET', headers: buildHeaders() },
|
|
160
170
|
)
|
|
161
171
|
if (!response.ok) return []
|
|
@@ -18,7 +18,7 @@ const usedBase = createSubResourcePlugin('used', 'used')
|
|
|
18
18
|
/**
|
|
19
19
|
* Combined relations plugin that registers contracts, uses, and used sub-resources.
|
|
20
20
|
*
|
|
21
|
-
* @param {object} [options
|
|
21
|
+
* @param {object} [options] Plugin options
|
|
22
22
|
* @return {Function} Plugin factory
|
|
23
23
|
*
|
|
24
24
|
* @example
|
|
@@ -124,21 +124,21 @@ export function searchPlugin() {
|
|
|
124
124
|
getters: {
|
|
125
125
|
/**
|
|
126
126
|
* The current search result objects.
|
|
127
|
-
* @param {object} state
|
|
127
|
+
* @param {object} state Pinia state
|
|
128
128
|
* @return {Array}
|
|
129
129
|
*/
|
|
130
130
|
searchCollection: (state) => state._searchCollection,
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
133
|
* Pagination state for the last search fetch.
|
|
134
|
-
* @param {object} state
|
|
134
|
+
* @param {object} state Pinia state
|
|
135
135
|
* @return {{ total: number, page: number, pages: number, limit: number }}
|
|
136
136
|
*/
|
|
137
137
|
searchPagination: (state) => state._searchPagination,
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
140
|
* True while a search fetch is in progress.
|
|
141
|
-
* @param {object} state
|
|
141
|
+
* @param {object} state Pinia state
|
|
142
142
|
* @return {boolean}
|
|
143
143
|
*/
|
|
144
144
|
searchLoading: (state) => state._searchLoading,
|
|
@@ -146,7 +146,7 @@ export function searchPlugin() {
|
|
|
146
146
|
/**
|
|
147
147
|
* The schema object for the current search register/schema pair.
|
|
148
148
|
* Populated automatically by `refetchSearchCollection`.
|
|
149
|
-
* @param {object} state
|
|
149
|
+
* @param {object} state Pinia state
|
|
150
150
|
* @return {object|null}
|
|
151
151
|
*/
|
|
152
152
|
searchSchema: (state) => state._searchSchema,
|
|
@@ -154,7 +154,7 @@ export function searchPlugin() {
|
|
|
154
154
|
/**
|
|
155
155
|
* The register object for the current search register/schema pair.
|
|
156
156
|
* Populated automatically by `refetchSearchCollection`.
|
|
157
|
-
* @param {object} state
|
|
157
|
+
* @param {object} state Pinia state
|
|
158
158
|
* @return {object|null}
|
|
159
159
|
*/
|
|
160
160
|
searchRegister: (state) => state._searchRegister,
|
|
@@ -162,7 +162,7 @@ export function searchPlugin() {
|
|
|
162
162
|
/**
|
|
163
163
|
* Facet data from the last search fetch, in CnIndexSidebar-compatible format:
|
|
164
164
|
* `{ fieldName: { values: [{ value, count }] } }`.
|
|
165
|
-
* @param {object} state
|
|
165
|
+
* @param {object} state Pinia state
|
|
166
166
|
* @return {object}
|
|
167
167
|
*/
|
|
168
168
|
searchFacets: (state) => state._searchFacets,
|
|
@@ -236,7 +236,20 @@ export function searchPlugin() {
|
|
|
236
236
|
* @return {Promise<Array>} The fetched collection (empty array on error)
|
|
237
237
|
*/
|
|
238
238
|
async refetchSearchCollection() {
|
|
239
|
-
const { register, schema, ...queryParams } = this.searchParams
|
|
239
|
+
const { register, schema, filters, ...queryParams } = this.searchParams
|
|
240
|
+
|
|
241
|
+
// Flatten the filters object into individual query params so the
|
|
242
|
+
// backend receives them as field-level filters (e.g. ?title=foo)
|
|
243
|
+
// instead of a single `filters=[object Object]` param.
|
|
244
|
+
if (filters && typeof filters === 'object') {
|
|
245
|
+
for (const [field, values] of Object.entries(filters)) {
|
|
246
|
+
if (Array.isArray(values) && values.length > 0) {
|
|
247
|
+
queryParams[field] = values
|
|
248
|
+
} else if (values && !Array.isArray(values)) {
|
|
249
|
+
queryParams[field] = values
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
240
253
|
|
|
241
254
|
if (!register || !schema) {
|
|
242
255
|
console.warn('[searchPlugin] refetchSearchCollection called without register/schema in searchParams')
|
|
@@ -263,7 +276,7 @@ export function searchPlugin() {
|
|
|
263
276
|
}
|
|
264
277
|
|
|
265
278
|
try {
|
|
266
|
-
const baseUrl = this._options?.baseUrl || '/apps/openregister/api/objects'
|
|
279
|
+
const baseUrl = this._options?.baseUrl || prefixUrl('/apps/openregister/api/objects')
|
|
267
280
|
const url = `${baseUrl}/${register}/${schema}` + buildQueryString(queryParams)
|
|
268
281
|
|
|
269
282
|
const response = await fetch(url, {
|