@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.
- package/README.md +226 -0
- package/css/index.css +5 -0
- package/dist/nextcloud-vue.cjs.js +79416 -7715
- package/dist/nextcloud-vue.cjs.js.map +1 -1
- package/dist/nextcloud-vue.css +3583 -504
- package/dist/nextcloud-vue.esm.js +79343 -7692
- package/dist/nextcloud-vue.esm.js.map +1 -1
- package/l10n/en.json +164 -0
- package/l10n/nl.json +164 -0
- package/package.json +104 -63
- package/src/components/CnActionsBar/CnActionsBar.vue +254 -0
- package/src/components/CnActionsBar/index.js +1 -0
- package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +570 -0
- package/src/components/CnAdvancedFormDialog/CnDataTab.vue +217 -0
- package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +121 -0
- package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +422 -0
- package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +247 -0
- package/src/components/CnAdvancedFormDialog/index.js +1 -0
- package/src/components/CnCard/CnCard.vue +415 -0
- package/src/components/CnCard/index.js +1 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +156 -152
- package/src/components/CnCardGrid/index.js +1 -1
- package/src/components/CnCellRenderer/CnCellRenderer.vue +132 -132
- package/src/components/CnCellRenderer/index.js +1 -1
- package/src/components/CnChartWidget/CnChartWidget.vue +346 -0
- package/src/components/CnChartWidget/index.js +1 -0
- package/src/components/CnConfigurationCard/CnConfigurationCard.vue +77 -77
- package/src/components/CnConfigurationCard/index.js +1 -1
- package/src/components/CnContextMenu/CnContextMenu.vue +142 -0
- package/src/components/CnContextMenu/index.js +1 -0
- package/src/components/CnCopyDialog/CnCopyDialog.vue +266 -0
- package/src/components/CnCopyDialog/index.js +1 -0
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +229 -0
- package/src/components/CnDashboardGrid/index.js +1 -0
- package/src/components/CnDashboardPage/CnDashboardPage.vue +397 -0
- package/src/components/CnDashboardPage/index.js +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +362 -354
- package/src/components/CnDataTable/index.js +1 -1
- package/src/components/CnDeleteDialog/CnDeleteDialog.vue +177 -0
- package/src/components/CnDeleteDialog/index.js +1 -0
- package/src/components/CnDetailCard/CnDetailCard.vue +225 -0
- package/src/components/CnDetailCard/index.js +1 -0
- package/src/components/CnDetailGrid/CnDetailGrid.vue +256 -0
- package/src/components/CnDetailGrid/index.js +1 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +432 -0
- package/src/components/CnDetailPage/index.js +1 -0
- package/src/components/CnFacetSidebar/CnFacetSidebar.vue +234 -223
- package/src/components/CnFacetSidebar/index.js +1 -1
- package/src/components/CnFilterBar/CnFilterBar.vue +153 -152
- package/src/components/CnFilterBar/index.js +1 -1
- package/src/components/CnFormDialog/CnFormDialog.vue +1047 -0
- package/src/components/CnFormDialog/index.js +1 -0
- package/src/components/CnIcon/CnIcon.vue +89 -0
- package/src/components/CnIcon/index.js +1 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +980 -682
- package/src/components/CnIndexPage/index.js +1 -1
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +536 -0
- package/src/components/CnIndexSidebar/index.js +1 -0
- package/src/components/CnInfoWidget/CnInfoWidget.vue +219 -0
- package/src/components/CnInfoWidget/index.js +1 -0
- package/src/components/CnItemCard/CnItemCard.vue +134 -0
- package/src/components/CnItemCard/index.js +1 -0
- package/src/components/CnJsonViewer/CnJsonViewer.vue +312 -0
- package/src/components/CnJsonViewer/index.js +1 -0
- package/src/components/CnKpiGrid/CnKpiGrid.vue +93 -89
- package/src/components/CnKpiGrid/index.js +1 -1
- package/src/components/CnMassActionBar/CnMassActionBar.vue +161 -160
- package/src/components/CnMassActionBar/index.js +1 -1
- package/src/components/CnMassCopyDialog/CnMassCopyDialog.vue +327 -320
- package/src/components/CnMassCopyDialog/index.js +1 -1
- package/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue +245 -238
- package/src/components/CnMassDeleteDialog/index.js +1 -1
- package/src/components/CnMassExportDialog/CnMassExportDialog.vue +191 -190
- package/src/components/CnMassExportDialog/index.js +1 -1
- package/src/components/CnMassImportDialog/CnMassImportDialog.vue +494 -491
- package/src/components/CnMassImportDialog/index.js +1 -1
- package/src/components/CnNoteCard/CnNoteCard.vue +149 -0
- package/src/components/CnNoteCard/index.js +1 -0
- package/src/components/CnNotesCard/CnNotesCard.vue +416 -0
- package/src/components/CnNotesCard/index.js +1 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +294 -292
- package/src/components/CnObjectCard/index.js +1 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +854 -0
- package/src/components/CnObjectDataWidget/index.js +1 -0
- package/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +289 -0
- package/src/components/CnObjectMetadataWidget/index.js +1 -0
- package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +369 -0
- package/src/components/CnObjectSidebar/CnFilesTab.vue +287 -0
- package/src/components/CnObjectSidebar/CnNotesTab.vue +250 -0
- package/src/components/CnObjectSidebar/CnObjectSidebar.vue +255 -0
- package/src/components/CnObjectSidebar/CnTagsTab.vue +259 -0
- package/src/components/CnObjectSidebar/CnTasksTab.vue +483 -0
- package/src/components/CnObjectSidebar/index.js +6 -0
- package/src/components/CnPageHeader/CnPageHeader.vue +61 -0
- package/src/components/CnPageHeader/index.js +1 -0
- package/src/components/CnPagination/CnPagination.vue +253 -252
- package/src/components/CnPagination/index.js +1 -1
- package/src/components/CnProgressBar/CnProgressBar.vue +262 -0
- package/src/components/CnProgressBar/index.js +1 -0
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +793 -0
- package/src/components/CnRegisterMapping/index.js +1 -0
- package/src/components/CnRowActions/CnRowActions.vue +95 -73
- package/src/components/CnRowActions/index.js +1 -1
- package/src/components/CnSchemaFormDialog/CnSchemaConfigurationTab.vue +226 -0
- package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +788 -0
- package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +305 -0
- package/src/components/CnSchemaFormDialog/CnSchemaPropertyActions.vue +1398 -0
- package/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue +236 -0
- package/src/components/CnSchemaFormDialog/index.js +1 -0
- package/src/components/CnSettingsCard/CnSettingsCard.vue +92 -92
- package/src/components/CnSettingsCard/index.js +1 -1
- package/src/components/CnSettingsSection/CnSettingsSection.vue +267 -266
- package/src/components/CnSettingsSection/index.js +1 -1
- package/src/components/CnStatsBlock/CnStatsBlock.vue +437 -366
- package/src/components/CnStatsBlock/index.js +1 -1
- package/src/components/CnStatsPanel/CnStatsPanel.vue +321 -0
- package/src/components/CnStatsPanel/index.js +1 -0
- package/src/components/CnStatusBadge/CnStatusBadge.vue +90 -77
- package/src/components/CnStatusBadge/index.js +1 -1
- package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +545 -0
- package/src/components/CnTabbedFormDialog/index.js +1 -0
- package/src/components/CnTableWidget/CnTableWidget.vue +333 -0
- package/src/components/CnTableWidget/index.js +1 -0
- package/src/components/CnTasksCard/CnTasksCard.vue +374 -0
- package/src/components/CnTasksCard/index.js +1 -0
- package/src/components/CnTileWidget/CnTileWidget.vue +159 -0
- package/src/components/CnTileWidget/index.js +1 -0
- package/src/components/CnTimelineStages/CnTimelineStages.vue +294 -0
- package/src/components/CnTimelineStages/index.js +1 -0
- package/src/components/CnUserActionMenu/CnUserActionMenu.vue +436 -0
- package/src/components/CnUserActionMenu/index.js +1 -0
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +313 -312
- package/src/components/CnVersionInfoCard/index.js +1 -1
- package/src/components/CnWidgetRenderer/CnWidgetRenderer.vue +180 -0
- package/src/components/CnWidgetRenderer/index.js +1 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +248 -0
- package/src/components/CnWidgetWrapper/index.js +1 -0
- package/src/components/index.js +57 -25
- package/src/composables/index.js +5 -3
- package/src/composables/useContextMenu.js +126 -0
- package/src/composables/useDashboardView.js +286 -0
- package/src/composables/useDetailView.js +290 -132
- package/src/composables/useListView.js +364 -153
- package/src/composables/useSubResource.js +142 -142
- package/src/constants/metadata.js +30 -0
- package/src/css/CnSchemaFormDialog.css +546 -0
- package/src/css/__sample_nextcloud_tokens.css +110 -0
- package/src/css/actions-bar.css +54 -0
- package/src/css/badge.css +83 -51
- package/src/css/card.css +129 -128
- package/src/css/context-menu.css +20 -0
- package/src/css/dashboard.css +70 -0
- package/src/css/detail-page.css +235 -0
- package/src/css/detail.css +68 -68
- package/src/css/index-page.css +44 -0
- package/src/css/index-sidebar.css +193 -0
- package/src/css/index.css +17 -8
- package/src/css/layout.css +90 -90
- package/src/css/page-header.css +35 -0
- package/src/css/pagination.css +72 -72
- package/src/css/table.css +142 -143
- package/src/css/timeline-stages.css +220 -0
- package/src/css/utilities.css +46 -46
- package/src/index.js +95 -50
- package/src/l10n/index.js +12 -0
- package/src/mixins/gridLayout.js +118 -0
- package/src/store/createCrudStore.d.ts +350 -0
- package/src/store/createCrudStore.js +413 -0
- package/src/store/createSubResourcePlugin.js +125 -135
- package/src/store/index.js +4 -3
- package/src/store/pluginMerge.js +55 -0
- package/src/store/plugins/auditTrails.js +357 -17
- package/src/store/plugins/files.js +250 -186
- package/src/store/plugins/index.js +8 -4
- package/src/store/plugins/lifecycle.js +180 -180
- package/src/store/plugins/logs.d.ts +22 -0
- package/src/store/plugins/logs.js +172 -0
- package/src/store/plugins/registerMapping.js +195 -0
- package/src/store/plugins/relations.js +68 -68
- package/src/store/plugins/search.js +385 -0
- package/src/store/plugins/selection.js +104 -0
- package/src/store/useObjectStore.js +793 -625
- package/src/types/auditTrail.d.ts +32 -32
- package/src/types/file.d.ts +23 -23
- package/src/types/index.d.ts +67 -35
- package/src/types/notification.d.ts +36 -36
- package/src/types/object.d.ts +40 -40
- package/src/types/organisation.d.ts +41 -41
- package/src/types/register.d.ts +25 -25
- package/src/types/schema.d.ts +39 -39
- package/src/types/shared.d.ts +79 -79
- package/src/types/source.d.ts +14 -14
- package/src/types/task.d.ts +31 -31
- package/src/utils/errors.js +96 -96
- package/src/utils/getTheme.js +9 -0
- package/src/utils/headers.js +80 -44
- package/src/utils/id.js +13 -0
- package/src/utils/index.js +4 -3
- package/src/utils/schema.js +423 -287
- package/src/utils/widgetVisibility.js +162 -0
- package/src/components/CnDetailViewLayout/CnDetailViewLayout.vue +0 -88
- package/src/components/CnDetailViewLayout/index.js +0 -1
- package/src/components/CnEmptyState/CnEmptyState.vue +0 -78
- package/src/components/CnEmptyState/index.js +0 -1
- package/src/components/CnListViewLayout/CnListViewLayout.vue +0 -80
- package/src/components/CnListViewLayout/index.js +0 -1
- package/src/components/CnViewModeToggle/CnViewModeToggle.vue +0 -77
- 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
|
|
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]
|
|
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
|
|
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
|
|
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
|
+
}
|