@conduction/nextcloud-vue 0.1.0-beta.3 → 0.1.0-beta.5
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 -226
- package/dist/nextcloud-vue.cjs +67614 -0
- package/dist/nextcloud-vue.cjs.js +58386 -6112
- package/dist/nextcloud-vue.cjs.js.map +1 -1
- package/dist/nextcloud-vue.cjs.map +1 -0
- package/dist/nextcloud-vue.css +1819 -285
- package/dist/nextcloud-vue.esm.js +58342 -6088
- package/dist/nextcloud-vue.esm.js.map +1 -1
- package/package.json +82 -62
- package/src/components/CnActionsBar/CnActionsBar.vue +17 -7
- package/src/components/CnActionsBar/index.js +1 -1
- package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +579 -0
- package/src/components/CnAdvancedFormDialog/CnDataTab.vue +217 -0
- package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +121 -0
- package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +418 -0
- package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +247 -0
- package/src/components/CnAdvancedFormDialog/index.js +1 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +1 -1
- package/src/components/CnCardGrid/index.js +1 -1
- package/src/components/CnCellRenderer/index.js +1 -1
- package/src/components/CnChartWidget/CnChartWidget.vue +320 -0
- package/src/components/CnChartWidget/index.js +1 -0
- package/src/components/CnConfigurationCard/index.js +1 -1
- package/src/components/CnCopyDialog/CnCopyDialog.vue +250 -250
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +225 -0
- package/src/components/CnDashboardGrid/index.js +1 -0
- package/src/components/CnDashboardPage/CnDashboardPage.vue +390 -0
- package/src/components/CnDashboardPage/index.js +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +1 -1
- package/src/components/CnDataTable/index.js +1 -1
- package/src/components/CnDeleteDialog/CnDeleteDialog.vue +170 -170
- package/src/components/CnDetailCard/CnDetailCard.vue +214 -0
- package/src/components/CnDetailCard/index.js +1 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +285 -0
- package/src/components/CnDetailPage/index.js +1 -0
- package/src/components/CnFacetSidebar/CnFacetSidebar.vue +9 -1
- package/src/components/CnFacetSidebar/index.js +1 -1
- package/src/components/CnFilterBar/index.js +1 -1
- package/src/components/CnFormDialog/CnFormDialog.vue +302 -11
- package/src/components/CnIcon/index.js +1 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +71 -3
- package/src/components/CnIndexPage/index.js +1 -1
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +121 -102
- package/src/components/CnIndexSidebar/index.js +1 -1
- package/src/components/CnItemCard/CnItemCard.vue +132 -0
- package/src/components/CnItemCard/index.js +1 -0
- package/src/components/CnKpiGrid/index.js +1 -1
- package/src/components/CnMassActionBar/index.js +1 -1
- package/src/components/CnMassCopyDialog/index.js +1 -1
- package/src/components/CnMassDeleteDialog/index.js +1 -1
- package/src/components/CnMassExportDialog/index.js +1 -1
- 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 +413 -0
- package/src/components/CnNotesCard/index.js +1 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +1 -1
- package/src/components/CnObjectCard/index.js +1 -1
- package/src/components/CnObjectSidebar/CnObjectSidebar.vue +876 -0
- package/src/components/CnObjectSidebar/index.js +1 -0
- package/src/components/CnPageHeader/index.js +1 -1
- package/src/components/CnPagination/index.js +1 -1
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +792 -792
- package/src/components/CnRowActions/CnRowActions.vue +25 -3
- package/src/components/CnRowActions/index.js +1 -1
- package/src/components/CnSchemaFormDialog/CnSchemaConfigurationTab.vue +226 -0
- package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +787 -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/index.js +1 -1
- package/src/components/CnSettingsSection/index.js +1 -1
- package/src/components/CnStatsBlock/CnStatsBlock.vue +62 -8
- package/src/components/CnStatsBlock/index.js +1 -1
- package/src/components/CnStatusBadge/index.js +1 -1
- package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +540 -0
- package/src/components/CnTabbedFormDialog/index.js +1 -0
- package/src/components/CnTasksCard/CnTasksCard.vue +373 -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 +292 -0
- package/src/components/CnTimelineStages/index.js +1 -0
- package/src/components/CnUserActionMenu/CnUserActionMenu.vue +435 -0
- package/src/components/CnUserActionMenu/index.js +1 -0
- 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 +211 -0
- package/src/components/CnWidgetWrapper/index.js +1 -0
- package/src/components/index.js +43 -29
- package/src/composables/index.js +4 -3
- package/src/composables/useDashboardView.js +240 -0
- package/src/composables/useDetailView.js +289 -132
- package/src/composables/useListView.js +363 -362
- package/src/composables/useSubResource.js +142 -142
- package/src/constants/metadata.js +30 -30
- package/src/css/CnSchemaFormDialog.css +546 -0
- package/src/css/__sample_nextcloud_tokens.css +110 -0
- package/src/css/actions-bar.css +48 -48
- package/src/css/badge.css +51 -51
- package/src/css/card.css +128 -128
- package/src/css/dashboard.css +70 -0
- package/src/css/detail-page.css +168 -0
- package/src/css/detail.css +68 -68
- package/src/css/index-page.css +44 -32
- package/src/css/index-sidebar.css +193 -187
- package/src/css/index.css +16 -12
- package/src/css/layout.css +90 -90
- package/src/css/page-header.css +33 -33
- package/src/css/pagination.css +72 -72
- package/src/css/table.css +142 -142
- package/src/css/timeline-stages.css +218 -0
- package/src/css/utilities.css +46 -46
- package/src/index.js +72 -53
- package/src/store/createSubResourcePlugin.js +135 -135
- package/src/store/index.js +3 -3
- package/src/store/plugins/auditTrails.js +17 -17
- package/src/store/plugins/files.js +250 -186
- package/src/store/plugins/index.js +7 -5
- package/src/store/plugins/lifecycle.js +180 -180
- package/src/store/plugins/relations.js +68 -68
- package/src/store/plugins/search.js +372 -0
- package/src/store/plugins/selection.js +104 -0
- package/src/store/useObjectStore.js +829 -686
- package/src/types/auditTrail.d.ts +32 -32
- package/src/types/file.d.ts +23 -23
- package/src/types/index.d.ts +35 -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/headers.js +68 -50
- package/src/utils/id.js +13 -0
- package/src/utils/index.js +3 -3
- package/src/utils/schema.js +422 -419
|
@@ -1,132 +1,289 @@
|
|
|
1
|
-
import { ref } from 'vue'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {
|
|
16
|
-
* @
|
|
17
|
-
*
|
|
18
|
-
* @
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
1
|
+
import { ref, computed, isRef, watch, onMounted } from 'vue'
|
|
2
|
+
import { useObjectStore } from '../store/index.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Composable for managing detail view state with full objectStore integration.
|
|
6
|
+
*
|
|
7
|
+
* When called with `objectType` and `id`, connects to the objectStore and handles
|
|
8
|
+
* fetching on mount, re-fetching on `id` changes, save/delete operations, and
|
|
9
|
+
* optional router navigation — eliminating boilerplate from every detail-view component.
|
|
10
|
+
*
|
|
11
|
+
* Backward-compatible: existing `useDetailView(options)` and `useDetailView()` calls
|
|
12
|
+
* continue to work without modification.
|
|
13
|
+
*
|
|
14
|
+
* @param {string|object} [objectTypeOrOptions] Object type slug (new API) or legacy options object
|
|
15
|
+
* @param {string|import('vue').Ref<string>} [id] Object ID or `'new'` for a new object
|
|
16
|
+
* @param {object} [options] Options (new API only)
|
|
17
|
+
* @param {object|null} [options.router] Vue Router instance — enables post-save/delete navigation
|
|
18
|
+
* @param {string|null} [options.listRouteName] Route name to navigate to after successful delete
|
|
19
|
+
* @param {string|null} [options.detailRouteName] Route name to navigate to after successful create
|
|
20
|
+
* @param {string} [options.nameField='title'] Field shown in error messages
|
|
21
|
+
* @return {object} Reactive state and operation functions
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // New API
|
|
25
|
+
* const { object, isNew, loading, saving, editing,
|
|
26
|
+
* onSave, confirmDelete, showDeleteDialog } = useDetailView('client', props.id, {
|
|
27
|
+
* router: useRouter(),
|
|
28
|
+
* listRouteName: 'ClientList',
|
|
29
|
+
* detailRouteName: 'ClientDetail',
|
|
30
|
+
* })
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Legacy API — still works
|
|
34
|
+
* const { objectData, editing, load, save, confirmDelete } = useDetailView({
|
|
35
|
+
* objectType: 'client',
|
|
36
|
+
* fetchFn: (type, id) => objectStore.fetchObject(type, id),
|
|
37
|
+
* saveFn: (type, data) => objectStore.saveObject(type, data),
|
|
38
|
+
* deleteFn: (type, id) => objectStore.deleteObject(type, id),
|
|
39
|
+
* })
|
|
40
|
+
*/
|
|
41
|
+
export function useDetailView(objectTypeOrOptions, id, options) {
|
|
42
|
+
// Backward compat: if first arg is an object or absent, delegate to legacy implementation
|
|
43
|
+
if (!objectTypeOrOptions || typeof objectTypeOrOptions === 'object') {
|
|
44
|
+
return useLegacyDetailView(objectTypeOrOptions || {})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ── New API ──────────────────────────────────────────────────────────
|
|
48
|
+
const objectType = objectTypeOrOptions
|
|
49
|
+
const opts = options || {}
|
|
50
|
+
const router = opts.router || null
|
|
51
|
+
const listRouteName = opts.listRouteName || null
|
|
52
|
+
const detailRouteName = opts.detailRouteName || null
|
|
53
|
+
|
|
54
|
+
// Normalise `id` to a ref so we can watch it
|
|
55
|
+
const idRef = isRef(id) ? id : ref(id)
|
|
56
|
+
|
|
57
|
+
const objectStore = useObjectStore()
|
|
58
|
+
|
|
59
|
+
// ── State refs ───────────────────────────────────────────────────────
|
|
60
|
+
const editing = ref(false)
|
|
61
|
+
const saving = ref(false)
|
|
62
|
+
const showDeleteDialog = ref(false)
|
|
63
|
+
const error = ref(null)
|
|
64
|
+
const validationErrors = ref(null)
|
|
65
|
+
|
|
66
|
+
// ── Computed refs from the store ─────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
const isNew = computed(() => !idRef.value || idRef.value === 'new')
|
|
69
|
+
|
|
70
|
+
const object = computed(() => {
|
|
71
|
+
if (isNew.value) return {}
|
|
72
|
+
return objectStore.getObject(objectType, idRef.value) || {}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const loading = computed(() => objectStore.loading[objectType] || false)
|
|
76
|
+
|
|
77
|
+
// ── Operations ───────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Save the object. Handles create (POST) and update (PUT) branches.
|
|
81
|
+
* On 422 validation error the `validationErrors` ref is populated.
|
|
82
|
+
* On successful create with `detailRouteName` set, the router navigates to the detail route.
|
|
83
|
+
* On successful update, `editing` is set to false and the object is re-fetched.
|
|
84
|
+
*
|
|
85
|
+
* @param {object} formData Data to save
|
|
86
|
+
* @return {Promise<object|null>} Saved object or null on error
|
|
87
|
+
*/
|
|
88
|
+
async function onSave(formData) {
|
|
89
|
+
saving.value = true
|
|
90
|
+
error.value = null
|
|
91
|
+
validationErrors.value = null
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const dataToSave = isNew.value ? formData : { ...formData, id: idRef.value }
|
|
95
|
+
const result = await objectStore.saveObject(objectType, dataToSave)
|
|
96
|
+
|
|
97
|
+
if (!result) {
|
|
98
|
+
// Store already set error; surface it
|
|
99
|
+
error.value = objectStore.errors[objectType]?.message || 'Failed to save'
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (isNew.value && router && detailRouteName) {
|
|
104
|
+
router.push({ name: detailRouteName, params: { id: result.id } })
|
|
105
|
+
} else {
|
|
106
|
+
editing.value = false
|
|
107
|
+
await objectStore.fetchObject(objectType, idRef.value)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return result
|
|
111
|
+
} catch (err) {
|
|
112
|
+
if (err?.response?.status === 422 || err?.status === 422) {
|
|
113
|
+
const data = err?.response?.data || err?.data || {}
|
|
114
|
+
validationErrors.value = data.errors || data
|
|
115
|
+
} else {
|
|
116
|
+
error.value = err.message || 'Failed to save'
|
|
117
|
+
}
|
|
118
|
+
return null
|
|
119
|
+
} finally {
|
|
120
|
+
saving.value = false
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Delete the current object. On success, navigate to `listRouteName` if configured.
|
|
126
|
+
* On failure, `error` ref is set.
|
|
127
|
+
*
|
|
128
|
+
* @return {Promise<boolean>} True if deleted successfully
|
|
129
|
+
*/
|
|
130
|
+
async function confirmDelete() {
|
|
131
|
+
error.value = null
|
|
132
|
+
try {
|
|
133
|
+
const success = await objectStore.deleteObject(objectType, idRef.value)
|
|
134
|
+
if (success) {
|
|
135
|
+
showDeleteDialog.value = false
|
|
136
|
+
if (router && listRouteName) {
|
|
137
|
+
router.push({ name: listRouteName })
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
error.value = objectStore.errors[objectType]?.message || 'Failed to delete'
|
|
141
|
+
}
|
|
142
|
+
return success
|
|
143
|
+
} catch (err) {
|
|
144
|
+
error.value = err.message || 'Failed to delete'
|
|
145
|
+
return false
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ── Lifecycle ────────────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
async function fetchIfNeeded(currentId) {
|
|
152
|
+
if (!currentId || currentId === 'new') return
|
|
153
|
+
await objectStore.fetchObject(objectType, currentId)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
onMounted(() => {
|
|
157
|
+
fetchIfNeeded(idRef.value)
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
watch(idRef, (newId) => {
|
|
161
|
+
fetchIfNeeded(newId)
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
// ── Return value ─────────────────────────────────────────────────────
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
// Store-derived
|
|
168
|
+
object,
|
|
169
|
+
loading,
|
|
170
|
+
// Computed state
|
|
171
|
+
isNew,
|
|
172
|
+
// Local state
|
|
173
|
+
editing,
|
|
174
|
+
saving,
|
|
175
|
+
showDeleteDialog,
|
|
176
|
+
error,
|
|
177
|
+
validationErrors,
|
|
178
|
+
// Operations
|
|
179
|
+
onSave,
|
|
180
|
+
confirmDelete,
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ── Legacy implementation ─────────────────────────────────────────────────────
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Legacy `useDetailView(options)` implementation.
|
|
188
|
+
* Preserved verbatim for backward compatibility.
|
|
189
|
+
*
|
|
190
|
+
* @param {object} options Legacy options object
|
|
191
|
+
* @param {string} [options.objectType] The registered object type slug
|
|
192
|
+
* @param {Function} [options.fetchFn] (type, id) => Promise<object>
|
|
193
|
+
* @param {Function} [options.saveFn] (type, data) => Promise<object>
|
|
194
|
+
* @param {Function} [options.deleteFn] (type, id) => Promise<boolean>
|
|
195
|
+
* @param {Function} [options.onSaved] Callback after successful save
|
|
196
|
+
* @param {Function} [options.onDeleted] Callback after successful delete
|
|
197
|
+
* @return {object} Reactive state and methods
|
|
198
|
+
*/
|
|
199
|
+
function useLegacyDetailView(options) {
|
|
200
|
+
const objectData = ref({})
|
|
201
|
+
const editing = ref(false)
|
|
202
|
+
const loading = ref(false)
|
|
203
|
+
const saving = ref(false)
|
|
204
|
+
const showDeleteDialog = ref(false)
|
|
205
|
+
const error = ref(null)
|
|
206
|
+
|
|
207
|
+
async function load(id) {
|
|
208
|
+
loading.value = true
|
|
209
|
+
error.value = null
|
|
210
|
+
try {
|
|
211
|
+
const result = options.fetchFn
|
|
212
|
+
? await options.fetchFn(options.objectType, id)
|
|
213
|
+
: null
|
|
214
|
+
if (result) {
|
|
215
|
+
objectData.value = { ...result }
|
|
216
|
+
}
|
|
217
|
+
return result
|
|
218
|
+
} catch (err) {
|
|
219
|
+
error.value = err.message || 'Failed to load'
|
|
220
|
+
return null
|
|
221
|
+
} finally {
|
|
222
|
+
loading.value = false
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function save(formData) {
|
|
227
|
+
saving.value = true
|
|
228
|
+
error.value = null
|
|
229
|
+
try {
|
|
230
|
+
const data = formData || objectData.value
|
|
231
|
+
const result = options.saveFn
|
|
232
|
+
? await options.saveFn(options.objectType, data)
|
|
233
|
+
: null
|
|
234
|
+
if (result) {
|
|
235
|
+
objectData.value = { ...result }
|
|
236
|
+
editing.value = false
|
|
237
|
+
if (options.onSaved) {
|
|
238
|
+
options.onSaved(result)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return result
|
|
242
|
+
} catch (err) {
|
|
243
|
+
error.value = err.message || 'Failed to save'
|
|
244
|
+
return null
|
|
245
|
+
} finally {
|
|
246
|
+
saving.value = false
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function confirmDelete() {
|
|
251
|
+
showDeleteDialog.value = true
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function executeDelete(id) {
|
|
255
|
+
const deleteId = id || objectData.value.id
|
|
256
|
+
loading.value = true
|
|
257
|
+
error.value = null
|
|
258
|
+
try {
|
|
259
|
+
const success = options.deleteFn
|
|
260
|
+
? await options.deleteFn(options.objectType, deleteId)
|
|
261
|
+
: false
|
|
262
|
+
if (success) {
|
|
263
|
+
showDeleteDialog.value = false
|
|
264
|
+
if (options.onDeleted) {
|
|
265
|
+
options.onDeleted()
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return success
|
|
269
|
+
} catch (err) {
|
|
270
|
+
error.value = err.message || 'Failed to delete'
|
|
271
|
+
return false
|
|
272
|
+
} finally {
|
|
273
|
+
loading.value = false
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
objectData,
|
|
279
|
+
editing,
|
|
280
|
+
loading,
|
|
281
|
+
saving,
|
|
282
|
+
showDeleteDialog,
|
|
283
|
+
error,
|
|
284
|
+
load,
|
|
285
|
+
save,
|
|
286
|
+
confirmDelete,
|
|
287
|
+
executeDelete,
|
|
288
|
+
}
|
|
289
|
+
}
|