@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.
Files changed (142) hide show
  1. package/README.md +226 -226
  2. package/dist/nextcloud-vue.cjs +67614 -0
  3. package/dist/nextcloud-vue.cjs.js +58386 -6112
  4. package/dist/nextcloud-vue.cjs.js.map +1 -1
  5. package/dist/nextcloud-vue.cjs.map +1 -0
  6. package/dist/nextcloud-vue.css +1819 -285
  7. package/dist/nextcloud-vue.esm.js +58342 -6088
  8. package/dist/nextcloud-vue.esm.js.map +1 -1
  9. package/package.json +82 -62
  10. package/src/components/CnActionsBar/CnActionsBar.vue +17 -7
  11. package/src/components/CnActionsBar/index.js +1 -1
  12. package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +579 -0
  13. package/src/components/CnAdvancedFormDialog/CnDataTab.vue +217 -0
  14. package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +121 -0
  15. package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +418 -0
  16. package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +247 -0
  17. package/src/components/CnAdvancedFormDialog/index.js +1 -0
  18. package/src/components/CnCardGrid/CnCardGrid.vue +1 -1
  19. package/src/components/CnCardGrid/index.js +1 -1
  20. package/src/components/CnCellRenderer/index.js +1 -1
  21. package/src/components/CnChartWidget/CnChartWidget.vue +320 -0
  22. package/src/components/CnChartWidget/index.js +1 -0
  23. package/src/components/CnConfigurationCard/index.js +1 -1
  24. package/src/components/CnCopyDialog/CnCopyDialog.vue +250 -250
  25. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +225 -0
  26. package/src/components/CnDashboardGrid/index.js +1 -0
  27. package/src/components/CnDashboardPage/CnDashboardPage.vue +390 -0
  28. package/src/components/CnDashboardPage/index.js +1 -0
  29. package/src/components/CnDataTable/CnDataTable.vue +1 -1
  30. package/src/components/CnDataTable/index.js +1 -1
  31. package/src/components/CnDeleteDialog/CnDeleteDialog.vue +170 -170
  32. package/src/components/CnDetailCard/CnDetailCard.vue +214 -0
  33. package/src/components/CnDetailCard/index.js +1 -0
  34. package/src/components/CnDetailPage/CnDetailPage.vue +285 -0
  35. package/src/components/CnDetailPage/index.js +1 -0
  36. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +9 -1
  37. package/src/components/CnFacetSidebar/index.js +1 -1
  38. package/src/components/CnFilterBar/index.js +1 -1
  39. package/src/components/CnFormDialog/CnFormDialog.vue +302 -11
  40. package/src/components/CnIcon/index.js +1 -1
  41. package/src/components/CnIndexPage/CnIndexPage.vue +71 -3
  42. package/src/components/CnIndexPage/index.js +1 -1
  43. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +121 -102
  44. package/src/components/CnIndexSidebar/index.js +1 -1
  45. package/src/components/CnItemCard/CnItemCard.vue +132 -0
  46. package/src/components/CnItemCard/index.js +1 -0
  47. package/src/components/CnKpiGrid/index.js +1 -1
  48. package/src/components/CnMassActionBar/index.js +1 -1
  49. package/src/components/CnMassCopyDialog/index.js +1 -1
  50. package/src/components/CnMassDeleteDialog/index.js +1 -1
  51. package/src/components/CnMassExportDialog/index.js +1 -1
  52. package/src/components/CnMassImportDialog/index.js +1 -1
  53. package/src/components/CnNoteCard/CnNoteCard.vue +149 -0
  54. package/src/components/CnNoteCard/index.js +1 -0
  55. package/src/components/CnNotesCard/CnNotesCard.vue +413 -0
  56. package/src/components/CnNotesCard/index.js +1 -0
  57. package/src/components/CnObjectCard/CnObjectCard.vue +1 -1
  58. package/src/components/CnObjectCard/index.js +1 -1
  59. package/src/components/CnObjectSidebar/CnObjectSidebar.vue +876 -0
  60. package/src/components/CnObjectSidebar/index.js +1 -0
  61. package/src/components/CnPageHeader/index.js +1 -1
  62. package/src/components/CnPagination/index.js +1 -1
  63. package/src/components/CnRegisterMapping/CnRegisterMapping.vue +792 -792
  64. package/src/components/CnRowActions/CnRowActions.vue +25 -3
  65. package/src/components/CnRowActions/index.js +1 -1
  66. package/src/components/CnSchemaFormDialog/CnSchemaConfigurationTab.vue +226 -0
  67. package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +787 -0
  68. package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +305 -0
  69. package/src/components/CnSchemaFormDialog/CnSchemaPropertyActions.vue +1398 -0
  70. package/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue +236 -0
  71. package/src/components/CnSchemaFormDialog/index.js +1 -0
  72. package/src/components/CnSettingsCard/index.js +1 -1
  73. package/src/components/CnSettingsSection/index.js +1 -1
  74. package/src/components/CnStatsBlock/CnStatsBlock.vue +62 -8
  75. package/src/components/CnStatsBlock/index.js +1 -1
  76. package/src/components/CnStatusBadge/index.js +1 -1
  77. package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +540 -0
  78. package/src/components/CnTabbedFormDialog/index.js +1 -0
  79. package/src/components/CnTasksCard/CnTasksCard.vue +373 -0
  80. package/src/components/CnTasksCard/index.js +1 -0
  81. package/src/components/CnTileWidget/CnTileWidget.vue +159 -0
  82. package/src/components/CnTileWidget/index.js +1 -0
  83. package/src/components/CnTimelineStages/CnTimelineStages.vue +292 -0
  84. package/src/components/CnTimelineStages/index.js +1 -0
  85. package/src/components/CnUserActionMenu/CnUserActionMenu.vue +435 -0
  86. package/src/components/CnUserActionMenu/index.js +1 -0
  87. package/src/components/CnVersionInfoCard/index.js +1 -1
  88. package/src/components/CnWidgetRenderer/CnWidgetRenderer.vue +180 -0
  89. package/src/components/CnWidgetRenderer/index.js +1 -0
  90. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +211 -0
  91. package/src/components/CnWidgetWrapper/index.js +1 -0
  92. package/src/components/index.js +43 -29
  93. package/src/composables/index.js +4 -3
  94. package/src/composables/useDashboardView.js +240 -0
  95. package/src/composables/useDetailView.js +289 -132
  96. package/src/composables/useListView.js +363 -362
  97. package/src/composables/useSubResource.js +142 -142
  98. package/src/constants/metadata.js +30 -30
  99. package/src/css/CnSchemaFormDialog.css +546 -0
  100. package/src/css/__sample_nextcloud_tokens.css +110 -0
  101. package/src/css/actions-bar.css +48 -48
  102. package/src/css/badge.css +51 -51
  103. package/src/css/card.css +128 -128
  104. package/src/css/dashboard.css +70 -0
  105. package/src/css/detail-page.css +168 -0
  106. package/src/css/detail.css +68 -68
  107. package/src/css/index-page.css +44 -32
  108. package/src/css/index-sidebar.css +193 -187
  109. package/src/css/index.css +16 -12
  110. package/src/css/layout.css +90 -90
  111. package/src/css/page-header.css +33 -33
  112. package/src/css/pagination.css +72 -72
  113. package/src/css/table.css +142 -142
  114. package/src/css/timeline-stages.css +218 -0
  115. package/src/css/utilities.css +46 -46
  116. package/src/index.js +72 -53
  117. package/src/store/createSubResourcePlugin.js +135 -135
  118. package/src/store/index.js +3 -3
  119. package/src/store/plugins/auditTrails.js +17 -17
  120. package/src/store/plugins/files.js +250 -186
  121. package/src/store/plugins/index.js +7 -5
  122. package/src/store/plugins/lifecycle.js +180 -180
  123. package/src/store/plugins/relations.js +68 -68
  124. package/src/store/plugins/search.js +372 -0
  125. package/src/store/plugins/selection.js +104 -0
  126. package/src/store/useObjectStore.js +829 -686
  127. package/src/types/auditTrail.d.ts +32 -32
  128. package/src/types/file.d.ts +23 -23
  129. package/src/types/index.d.ts +35 -35
  130. package/src/types/notification.d.ts +36 -36
  131. package/src/types/object.d.ts +40 -40
  132. package/src/types/organisation.d.ts +41 -41
  133. package/src/types/register.d.ts +25 -25
  134. package/src/types/schema.d.ts +39 -39
  135. package/src/types/shared.d.ts +79 -79
  136. package/src/types/source.d.ts +14 -14
  137. package/src/types/task.d.ts +31 -31
  138. package/src/utils/errors.js +96 -96
  139. package/src/utils/headers.js +68 -50
  140. package/src/utils/id.js +13 -0
  141. package/src/utils/index.js +3 -3
  142. package/src/utils/schema.js +422 -419
@@ -1,132 +1,289 @@
1
- import { ref } from 'vue'
2
-
3
- /**
4
- * Composable for managing detail view state: loading, editing, deleting.
5
- *
6
- * Extracts the load/edit/delete pattern found in every detail view
7
- * across Pipelinq and Procest.
8
- *
9
- * @param {object} options Configuration options
10
- * @param {string} options.objectType The registered object type slug
11
- * @param {Function} options.fetchFn (type, id) => Promise<object>
12
- * @param {Function} options.saveFn (type, data) => Promise<object>
13
- * @param {Function} options.deleteFn (type, id) => Promise<boolean>
14
- * @param {Function} [options.onSaved] Callback after successful save
15
- * @param {Function} [options.onDeleted] Callback after successful delete
16
- * @return {object} Reactive state and methods
17
- *
18
- * @example
19
- * import { useDetailView } from '@conduction/nextcloud-vue'
20
- *
21
- * const { objectData, editing, loading, showDeleteDialog, load, save, confirmDelete, executeDelete } = useDetailView({
22
- * objectType: 'client',
23
- * fetchFn: (type, id) => objectStore.fetchObject(type, id),
24
- * saveFn: (type, data) => objectStore.saveObject(type, data),
25
- * deleteFn: (type, id) => objectStore.deleteObject(type, id),
26
- * onSaved: (result) => router.push(`/clients/${result.id}`),
27
- * onDeleted: () => router.push('/clients'),
28
- * })
29
- */
30
- export function useDetailView(options) {
31
- const objectData = ref({})
32
- const editing = ref(false)
33
- const loading = ref(false)
34
- const saving = ref(false)
35
- const showDeleteDialog = ref(false)
36
- const error = ref(null)
37
-
38
- /**
39
- * Load an object by ID.
40
- * @param {string} id Object ID
41
- * @return {Promise<object|null>}
42
- */
43
- async function load(id) {
44
- loading.value = true
45
- error.value = null
46
- try {
47
- const result = await options.fetchFn(options.objectType, id)
48
- if (result) {
49
- objectData.value = { ...result }
50
- }
51
- return result
52
- } catch (err) {
53
- error.value = err.message || 'Failed to load'
54
- return null
55
- } finally {
56
- loading.value = false
57
- }
58
- }
59
-
60
- /**
61
- * Save the current object data (create or update).
62
- * @param {object} [formData] Optional form data override (defaults to objectData)
63
- * @return {Promise<object|null>}
64
- */
65
- async function save(formData) {
66
- saving.value = true
67
- error.value = null
68
- try {
69
- const data = formData || objectData.value
70
- const result = await options.saveFn(options.objectType, data)
71
- if (result) {
72
- objectData.value = { ...result }
73
- editing.value = false
74
- if (options.onSaved) {
75
- options.onSaved(result)
76
- }
77
- }
78
- return result
79
- } catch (err) {
80
- error.value = err.message || 'Failed to save'
81
- return null
82
- } finally {
83
- saving.value = false
84
- }
85
- }
86
-
87
- /**
88
- * Show the delete confirmation dialog.
89
- */
90
- function confirmDelete() {
91
- showDeleteDialog.value = true
92
- }
93
-
94
- /**
95
- * Execute the delete operation.
96
- * @param {string} [id] Object ID (defaults to objectData.id)
97
- * @return {Promise<boolean>}
98
- */
99
- async function executeDelete(id) {
100
- const deleteId = id || objectData.value.id
101
- loading.value = true
102
- error.value = null
103
- try {
104
- const success = await options.deleteFn(options.objectType, deleteId)
105
- if (success) {
106
- showDeleteDialog.value = false
107
- if (options.onDeleted) {
108
- options.onDeleted()
109
- }
110
- }
111
- return success
112
- } catch (err) {
113
- error.value = err.message || 'Failed to delete'
114
- return false
115
- } finally {
116
- loading.value = false
117
- }
118
- }
119
-
120
- return {
121
- objectData,
122
- editing,
123
- loading,
124
- saving,
125
- showDeleteDialog,
126
- error,
127
- load,
128
- save,
129
- confirmDelete,
130
- executeDelete,
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
+ }