@conduction/nextcloud-vue 0.1.0-beta.1 → 0.1.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +226 -0
  2. package/css/index.css +5 -0
  3. package/dist/nextcloud-vue.cjs.js +79416 -7715
  4. package/dist/nextcloud-vue.cjs.js.map +1 -1
  5. package/dist/nextcloud-vue.css +3583 -504
  6. package/dist/nextcloud-vue.esm.js +79343 -7692
  7. package/dist/nextcloud-vue.esm.js.map +1 -1
  8. package/l10n/en.json +164 -0
  9. package/l10n/nl.json +164 -0
  10. package/package.json +104 -63
  11. package/src/components/CnActionsBar/CnActionsBar.vue +254 -0
  12. package/src/components/CnActionsBar/index.js +1 -0
  13. package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +570 -0
  14. package/src/components/CnAdvancedFormDialog/CnDataTab.vue +217 -0
  15. package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +121 -0
  16. package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +422 -0
  17. package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +247 -0
  18. package/src/components/CnAdvancedFormDialog/index.js +1 -0
  19. package/src/components/CnCard/CnCard.vue +415 -0
  20. package/src/components/CnCard/index.js +1 -0
  21. package/src/components/CnCardGrid/CnCardGrid.vue +156 -152
  22. package/src/components/CnCardGrid/index.js +1 -1
  23. package/src/components/CnCellRenderer/CnCellRenderer.vue +132 -132
  24. package/src/components/CnCellRenderer/index.js +1 -1
  25. package/src/components/CnChartWidget/CnChartWidget.vue +346 -0
  26. package/src/components/CnChartWidget/index.js +1 -0
  27. package/src/components/CnConfigurationCard/CnConfigurationCard.vue +77 -77
  28. package/src/components/CnConfigurationCard/index.js +1 -1
  29. package/src/components/CnContextMenu/CnContextMenu.vue +142 -0
  30. package/src/components/CnContextMenu/index.js +1 -0
  31. package/src/components/CnCopyDialog/CnCopyDialog.vue +266 -0
  32. package/src/components/CnCopyDialog/index.js +1 -0
  33. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +229 -0
  34. package/src/components/CnDashboardGrid/index.js +1 -0
  35. package/src/components/CnDashboardPage/CnDashboardPage.vue +397 -0
  36. package/src/components/CnDashboardPage/index.js +1 -0
  37. package/src/components/CnDataTable/CnDataTable.vue +362 -354
  38. package/src/components/CnDataTable/index.js +1 -1
  39. package/src/components/CnDeleteDialog/CnDeleteDialog.vue +177 -0
  40. package/src/components/CnDeleteDialog/index.js +1 -0
  41. package/src/components/CnDetailCard/CnDetailCard.vue +225 -0
  42. package/src/components/CnDetailCard/index.js +1 -0
  43. package/src/components/CnDetailGrid/CnDetailGrid.vue +256 -0
  44. package/src/components/CnDetailGrid/index.js +1 -0
  45. package/src/components/CnDetailPage/CnDetailPage.vue +432 -0
  46. package/src/components/CnDetailPage/index.js +1 -0
  47. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +234 -223
  48. package/src/components/CnFacetSidebar/index.js +1 -1
  49. package/src/components/CnFilterBar/CnFilterBar.vue +153 -152
  50. package/src/components/CnFilterBar/index.js +1 -1
  51. package/src/components/CnFormDialog/CnFormDialog.vue +1047 -0
  52. package/src/components/CnFormDialog/index.js +1 -0
  53. package/src/components/CnIcon/CnIcon.vue +89 -0
  54. package/src/components/CnIcon/index.js +1 -0
  55. package/src/components/CnIndexPage/CnIndexPage.vue +980 -682
  56. package/src/components/CnIndexPage/index.js +1 -1
  57. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +536 -0
  58. package/src/components/CnIndexSidebar/index.js +1 -0
  59. package/src/components/CnInfoWidget/CnInfoWidget.vue +219 -0
  60. package/src/components/CnInfoWidget/index.js +1 -0
  61. package/src/components/CnItemCard/CnItemCard.vue +134 -0
  62. package/src/components/CnItemCard/index.js +1 -0
  63. package/src/components/CnJsonViewer/CnJsonViewer.vue +312 -0
  64. package/src/components/CnJsonViewer/index.js +1 -0
  65. package/src/components/CnKpiGrid/CnKpiGrid.vue +93 -89
  66. package/src/components/CnKpiGrid/index.js +1 -1
  67. package/src/components/CnMassActionBar/CnMassActionBar.vue +161 -160
  68. package/src/components/CnMassActionBar/index.js +1 -1
  69. package/src/components/CnMassCopyDialog/CnMassCopyDialog.vue +327 -320
  70. package/src/components/CnMassCopyDialog/index.js +1 -1
  71. package/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue +245 -238
  72. package/src/components/CnMassDeleteDialog/index.js +1 -1
  73. package/src/components/CnMassExportDialog/CnMassExportDialog.vue +191 -190
  74. package/src/components/CnMassExportDialog/index.js +1 -1
  75. package/src/components/CnMassImportDialog/CnMassImportDialog.vue +494 -491
  76. package/src/components/CnMassImportDialog/index.js +1 -1
  77. package/src/components/CnNoteCard/CnNoteCard.vue +149 -0
  78. package/src/components/CnNoteCard/index.js +1 -0
  79. package/src/components/CnNotesCard/CnNotesCard.vue +416 -0
  80. package/src/components/CnNotesCard/index.js +1 -0
  81. package/src/components/CnObjectCard/CnObjectCard.vue +294 -292
  82. package/src/components/CnObjectCard/index.js +1 -1
  83. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +854 -0
  84. package/src/components/CnObjectDataWidget/index.js +1 -0
  85. package/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +289 -0
  86. package/src/components/CnObjectMetadataWidget/index.js +1 -0
  87. package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +369 -0
  88. package/src/components/CnObjectSidebar/CnFilesTab.vue +287 -0
  89. package/src/components/CnObjectSidebar/CnNotesTab.vue +250 -0
  90. package/src/components/CnObjectSidebar/CnObjectSidebar.vue +255 -0
  91. package/src/components/CnObjectSidebar/CnTagsTab.vue +259 -0
  92. package/src/components/CnObjectSidebar/CnTasksTab.vue +483 -0
  93. package/src/components/CnObjectSidebar/index.js +6 -0
  94. package/src/components/CnPageHeader/CnPageHeader.vue +61 -0
  95. package/src/components/CnPageHeader/index.js +1 -0
  96. package/src/components/CnPagination/CnPagination.vue +253 -252
  97. package/src/components/CnPagination/index.js +1 -1
  98. package/src/components/CnProgressBar/CnProgressBar.vue +262 -0
  99. package/src/components/CnProgressBar/index.js +1 -0
  100. package/src/components/CnRegisterMapping/CnRegisterMapping.vue +793 -0
  101. package/src/components/CnRegisterMapping/index.js +1 -0
  102. package/src/components/CnRowActions/CnRowActions.vue +95 -73
  103. package/src/components/CnRowActions/index.js +1 -1
  104. package/src/components/CnSchemaFormDialog/CnSchemaConfigurationTab.vue +226 -0
  105. package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +788 -0
  106. package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +305 -0
  107. package/src/components/CnSchemaFormDialog/CnSchemaPropertyActions.vue +1398 -0
  108. package/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue +236 -0
  109. package/src/components/CnSchemaFormDialog/index.js +1 -0
  110. package/src/components/CnSettingsCard/CnSettingsCard.vue +92 -92
  111. package/src/components/CnSettingsCard/index.js +1 -1
  112. package/src/components/CnSettingsSection/CnSettingsSection.vue +267 -266
  113. package/src/components/CnSettingsSection/index.js +1 -1
  114. package/src/components/CnStatsBlock/CnStatsBlock.vue +437 -366
  115. package/src/components/CnStatsBlock/index.js +1 -1
  116. package/src/components/CnStatsPanel/CnStatsPanel.vue +321 -0
  117. package/src/components/CnStatsPanel/index.js +1 -0
  118. package/src/components/CnStatusBadge/CnStatusBadge.vue +90 -77
  119. package/src/components/CnStatusBadge/index.js +1 -1
  120. package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +545 -0
  121. package/src/components/CnTabbedFormDialog/index.js +1 -0
  122. package/src/components/CnTableWidget/CnTableWidget.vue +333 -0
  123. package/src/components/CnTableWidget/index.js +1 -0
  124. package/src/components/CnTasksCard/CnTasksCard.vue +374 -0
  125. package/src/components/CnTasksCard/index.js +1 -0
  126. package/src/components/CnTileWidget/CnTileWidget.vue +159 -0
  127. package/src/components/CnTileWidget/index.js +1 -0
  128. package/src/components/CnTimelineStages/CnTimelineStages.vue +294 -0
  129. package/src/components/CnTimelineStages/index.js +1 -0
  130. package/src/components/CnUserActionMenu/CnUserActionMenu.vue +436 -0
  131. package/src/components/CnUserActionMenu/index.js +1 -0
  132. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +313 -312
  133. package/src/components/CnVersionInfoCard/index.js +1 -1
  134. package/src/components/CnWidgetRenderer/CnWidgetRenderer.vue +180 -0
  135. package/src/components/CnWidgetRenderer/index.js +1 -0
  136. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +248 -0
  137. package/src/components/CnWidgetWrapper/index.js +1 -0
  138. package/src/components/index.js +57 -25
  139. package/src/composables/index.js +5 -3
  140. package/src/composables/useContextMenu.js +126 -0
  141. package/src/composables/useDashboardView.js +286 -0
  142. package/src/composables/useDetailView.js +290 -132
  143. package/src/composables/useListView.js +364 -153
  144. package/src/composables/useSubResource.js +142 -142
  145. package/src/constants/metadata.js +30 -0
  146. package/src/css/CnSchemaFormDialog.css +546 -0
  147. package/src/css/__sample_nextcloud_tokens.css +110 -0
  148. package/src/css/actions-bar.css +54 -0
  149. package/src/css/badge.css +83 -51
  150. package/src/css/card.css +129 -128
  151. package/src/css/context-menu.css +20 -0
  152. package/src/css/dashboard.css +70 -0
  153. package/src/css/detail-page.css +235 -0
  154. package/src/css/detail.css +68 -68
  155. package/src/css/index-page.css +44 -0
  156. package/src/css/index-sidebar.css +193 -0
  157. package/src/css/index.css +17 -8
  158. package/src/css/layout.css +90 -90
  159. package/src/css/page-header.css +35 -0
  160. package/src/css/pagination.css +72 -72
  161. package/src/css/table.css +142 -143
  162. package/src/css/timeline-stages.css +220 -0
  163. package/src/css/utilities.css +46 -46
  164. package/src/index.js +95 -50
  165. package/src/l10n/index.js +12 -0
  166. package/src/mixins/gridLayout.js +118 -0
  167. package/src/store/createCrudStore.d.ts +350 -0
  168. package/src/store/createCrudStore.js +413 -0
  169. package/src/store/createSubResourcePlugin.js +125 -135
  170. package/src/store/index.js +4 -3
  171. package/src/store/pluginMerge.js +55 -0
  172. package/src/store/plugins/auditTrails.js +357 -17
  173. package/src/store/plugins/files.js +250 -186
  174. package/src/store/plugins/index.js +8 -4
  175. package/src/store/plugins/lifecycle.js +180 -180
  176. package/src/store/plugins/logs.d.ts +22 -0
  177. package/src/store/plugins/logs.js +172 -0
  178. package/src/store/plugins/registerMapping.js +195 -0
  179. package/src/store/plugins/relations.js +68 -68
  180. package/src/store/plugins/search.js +385 -0
  181. package/src/store/plugins/selection.js +104 -0
  182. package/src/store/useObjectStore.js +793 -625
  183. package/src/types/auditTrail.d.ts +32 -32
  184. package/src/types/file.d.ts +23 -23
  185. package/src/types/index.d.ts +67 -35
  186. package/src/types/notification.d.ts +36 -36
  187. package/src/types/object.d.ts +40 -40
  188. package/src/types/organisation.d.ts +41 -41
  189. package/src/types/register.d.ts +25 -25
  190. package/src/types/schema.d.ts +39 -39
  191. package/src/types/shared.d.ts +79 -79
  192. package/src/types/source.d.ts +14 -14
  193. package/src/types/task.d.ts +31 -31
  194. package/src/utils/errors.js +96 -96
  195. package/src/utils/getTheme.js +9 -0
  196. package/src/utils/headers.js +80 -44
  197. package/src/utils/id.js +13 -0
  198. package/src/utils/index.js +4 -3
  199. package/src/utils/schema.js +423 -287
  200. package/src/utils/widgetVisibility.js +162 -0
  201. package/src/components/CnDetailViewLayout/CnDetailViewLayout.vue +0 -88
  202. package/src/components/CnDetailViewLayout/index.js +0 -1
  203. package/src/components/CnEmptyState/CnEmptyState.vue +0 -78
  204. package/src/components/CnEmptyState/index.js +0 -1
  205. package/src/components/CnListViewLayout/CnListViewLayout.vue +0 -80
  206. package/src/components/CnListViewLayout/index.js +0 -1
  207. package/src/components/CnViewModeToggle/CnViewModeToggle.vue +0 -77
  208. package/src/components/CnViewModeToggle/index.js +0 -1
@@ -0,0 +1,162 @@
1
+ import axios from '@nextcloud/axios'
2
+ import { generateOcsUrl } from '@nextcloud/router'
3
+
4
+ /**
5
+ * Cached user groups — fetched once per session and reused.
6
+ * @type {{ userId: string|null, groups: string[]|null, promise: Promise|null }}
7
+ */
8
+ const _cache = {
9
+ userId: null,
10
+ groups: null,
11
+ promise: null,
12
+ }
13
+
14
+ /**
15
+ * Get the current Nextcloud user ID from OC.currentUser.
16
+ *
17
+ * @return {string|null} The current user ID, or null if not logged in
18
+ */
19
+ export function getCurrentUserId() {
20
+ return window.OC?.currentUser?.uid
21
+ || window.OC?.currentUser
22
+ || null
23
+ }
24
+
25
+ /**
26
+ * Fetch the current user's Nextcloud groups. Results are cached so the
27
+ * OCS API is only called once per page load.
28
+ *
29
+ * @return {Promise<string[]>} Array of group IDs the current user belongs to
30
+ */
31
+ export async function getCurrentUserGroups() {
32
+ const userId = getCurrentUserId()
33
+ if (!userId) {
34
+ return []
35
+ }
36
+
37
+ // Return cached result if we already fetched for this user
38
+ if (_cache.userId === userId && _cache.groups !== null) {
39
+ return _cache.groups
40
+ }
41
+
42
+ // If a fetch is already in progress for this user, await it
43
+ if (_cache.userId === userId && _cache.promise) {
44
+ return _cache.promise
45
+ }
46
+
47
+ _cache.userId = userId
48
+ _cache.promise = _fetchGroups(userId)
49
+
50
+ try {
51
+ _cache.groups = await _cache.promise
52
+ } catch {
53
+ _cache.groups = []
54
+ } finally {
55
+ _cache.promise = null
56
+ }
57
+
58
+ return _cache.groups
59
+ }
60
+
61
+ /**
62
+ * Internal: fetch groups from OCS API.
63
+ *
64
+ * @param {string} userId The user ID to look up
65
+ * @return {Promise<string[]>} Array of group IDs
66
+ */
67
+ async function _fetchGroups(userId) {
68
+ try {
69
+ const url = generateOcsUrl('/cloud/users/{userId}/groups', { userId })
70
+ const response = await axios.get(url)
71
+ const groups = response.data?.ocs?.data?.groups || []
72
+ return groups
73
+ } catch (error) {
74
+ console.error('[widgetVisibility] Failed to fetch user groups:', error)
75
+ return []
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Check whether a single widget is visible to the current user based on
81
+ * its `visibility` configuration.
82
+ *
83
+ * Visibility rules:
84
+ * - No `visibility` property -> visible to everyone
85
+ * - `visibility.users` contains the current user ID -> visible
86
+ * - `visibility.groups` overlaps with the user's groups -> visible
87
+ * - Both `users` and `groups` are specified -> either match grants access (OR logic)
88
+ * - Both are empty arrays -> visible to everyone
89
+ *
90
+ * @param {object} widget Widget definition object
91
+ * @param {object} [widget.visibility] Optional visibility configuration
92
+ * @param {string[]} [widget.visibility.users] User IDs who can see this widget
93
+ * @param {string[]} [widget.visibility.groups] Group names who can see this widget
94
+ * @param {string|null} userId Current user ID
95
+ * @param {string[]} userGroups Current user's group memberships
96
+ * @return {boolean} Whether the widget should be visible
97
+ */
98
+ export function isWidgetVisible(widget, userId, userGroups) {
99
+ const visibility = widget?.visibility
100
+ if (!visibility) {
101
+ return true
102
+ }
103
+
104
+ const allowedUsers = visibility.users || []
105
+ const allowedGroups = visibility.groups || []
106
+
107
+ // If both are empty, visible to everyone
108
+ if (allowedUsers.length === 0 && allowedGroups.length === 0) {
109
+ return true
110
+ }
111
+
112
+ // Check user match
113
+ if (allowedUsers.length > 0 && userId && allowedUsers.includes(userId)) {
114
+ return true
115
+ }
116
+
117
+ // Check group match
118
+ if (allowedGroups.length > 0 && userGroups.length > 0) {
119
+ const hasGroupMatch = allowedGroups.some(group => userGroups.includes(group))
120
+ if (hasGroupMatch) {
121
+ return true
122
+ }
123
+ }
124
+
125
+ return false
126
+ }
127
+
128
+ /**
129
+ * Filter an array of widget definitions by visibility for the current user.
130
+ *
131
+ * This is an async function because it may need to fetch the user's groups
132
+ * from the OCS API (cached after first call).
133
+ *
134
+ * @param {Array} widgets Array of widget definition objects
135
+ * @return {Promise<Array>} Filtered array of visible widgets
136
+ */
137
+ export async function filterWidgetsByVisibility(widgets) {
138
+ if (!widgets || widgets.length === 0) {
139
+ return []
140
+ }
141
+
142
+ // Quick path: if no widgets have visibility config, return all
143
+ const hasVisibilityConfig = widgets.some(w => w.visibility)
144
+ if (!hasVisibilityConfig) {
145
+ return widgets
146
+ }
147
+
148
+ const userId = getCurrentUserId()
149
+ const userGroups = await getCurrentUserGroups()
150
+
151
+ return widgets.filter(widget => isWidgetVisible(widget, userId, userGroups))
152
+ }
153
+
154
+ /**
155
+ * Reset the internal groups cache. Useful for testing or when user
156
+ * context changes.
157
+ */
158
+ export function resetVisibilityCache() {
159
+ _cache.userId = null
160
+ _cache.groups = null
161
+ _cache.promise = null
162
+ }
@@ -1,88 +0,0 @@
1
- <template>
2
- <div class="cn-detail-layout">
3
- <!-- Header -->
4
- <div class="cn-detail-layout__header">
5
- <NcButton @click="$emit('back')">
6
- <template #icon>
7
- <ArrowLeft :size="20" />
8
- </template>
9
- {{ backLabel }}
10
- </NcButton>
11
-
12
- <h2 class="cn-detail-layout__title">
13
- <slot name="title">{{ title }}</slot>
14
- </h2>
15
-
16
- <div class="cn-detail-layout__actions">
17
- <slot name="actions" />
18
- </div>
19
- </div>
20
-
21
- <!-- Loading state -->
22
- <div v-if="loading" class="cn-loading-container">
23
- <NcLoadingIcon :size="32" />
24
- </div>
25
-
26
- <!-- Main content -->
27
- <div v-else class="cn-detail-layout__content">
28
- <slot />
29
- </div>
30
-
31
- <!-- Delete confirmation dialog -->
32
- <slot name="dialogs" />
33
- </div>
34
- </template>
35
-
36
- <script>
37
- import { NcButton, NcLoadingIcon } from '@nextcloud/vue'
38
- import ArrowLeft from 'vue-material-design-icons/ArrowLeft.vue'
39
-
40
- /**
41
- * CnDetailViewLayout — Detail page layout with back button, title, actions, and content.
42
- *
43
- * Provides the standard structure for detail/edit views: back navigation,
44
- * page title, action buttons, and a content area. Supports loading state
45
- * and a dialogs slot for modals.
46
- *
47
- * @example
48
- * <CnDetailViewLayout
49
- * title="Client: Acme Corp"
50
- * :loading="isLoading"
51
- * @back="goBack">
52
- * <template #actions>
53
- * <NcButton @click="edit">Edit</NcButton>
54
- * <NcButton type="error" @click="confirmDelete">Delete</NcButton>
55
- * </template>
56
- * <div class="cn-detail-grid">
57
- * <div class="cn-detail-item">...</div>
58
- * </div>
59
- * </CnDetailViewLayout>
60
- */
61
- export default {
62
- name: 'CnDetailViewLayout',
63
-
64
- components: {
65
- NcButton,
66
- NcLoadingIcon,
67
- ArrowLeft,
68
- },
69
-
70
- props: {
71
- /** Page title */
72
- title: {
73
- type: String,
74
- default: '',
75
- },
76
- /** Whether data is loading */
77
- loading: {
78
- type: Boolean,
79
- default: false,
80
- },
81
- /** Back button label */
82
- backLabel: {
83
- type: String,
84
- default: 'Back',
85
- },
86
- },
87
- }
88
- </script>
@@ -1 +0,0 @@
1
- export { default as CnDetailViewLayout } from './CnDetailViewLayout.vue'
@@ -1,78 +0,0 @@
1
- <template>
2
- <NcEmptyContent :name="title" :description="description">
3
- <template #icon>
4
- <slot name="icon">
5
- <component :is="icon" v-if="icon" :size="64" />
6
- </slot>
7
- </template>
8
- <template v-if="actionLabel" #action>
9
- <slot name="action">
10
- <NcButton :type="actionType" @click="$emit('action')">
11
- {{ actionLabel }}
12
- </NcButton>
13
- </slot>
14
- </template>
15
- </NcEmptyContent>
16
- </template>
17
-
18
- <script>
19
- import { NcEmptyContent, NcButton } from '@nextcloud/vue'
20
-
21
- /**
22
- * CnEmptyState — Consistent empty state display wrapping NcEmptyContent.
23
- *
24
- * Provides a unified empty state pattern with icon, title, description,
25
- * and optional action button. Used across all list views.
26
- *
27
- * @example
28
- * <CnEmptyState
29
- * title="No clients yet"
30
- * description="Create your first client to get started"
31
- * action-label="New Client"
32
- * @action="createClient" />
33
- *
34
- * @example
35
- * <!-- With custom icon -->
36
- * <CnEmptyState title="No results">
37
- * <template #icon>
38
- * <Magnify :size="64" />
39
- * </template>
40
- * </CnEmptyState>
41
- */
42
- export default {
43
- name: 'CnEmptyState',
44
-
45
- components: {
46
- NcEmptyContent,
47
- NcButton,
48
- },
49
-
50
- props: {
51
- /** Main title text */
52
- title: {
53
- type: String,
54
- required: true,
55
- },
56
- /** Description text below the title */
57
- description: {
58
- type: String,
59
- default: '',
60
- },
61
- /** Vue component for the icon (e.g., imported material design icon) */
62
- icon: {
63
- type: [Object, null],
64
- default: null,
65
- },
66
- /** Action button label. If empty, no button is shown. */
67
- actionLabel: {
68
- type: String,
69
- default: '',
70
- },
71
- /** NcButton type for the action button */
72
- actionType: {
73
- type: String,
74
- default: 'primary',
75
- },
76
- },
77
- }
78
- </script>
@@ -1 +0,0 @@
1
- export { default as CnEmptyState } from './CnEmptyState.vue'
@@ -1,80 +0,0 @@
1
- <template>
2
- <div class="cn-list-layout">
3
- <!-- Header -->
4
- <div class="cn-list-layout__header">
5
- <div class="cn-list-layout__title">
6
- <h2>{{ title }}</h2>
7
- <span v-if="totalItems > 0" class="cn-list-layout__count">({{ totalItems }})</span>
8
- </div>
9
- <div class="cn-list-layout__actions">
10
- <slot name="actions" />
11
- </div>
12
- </div>
13
-
14
- <!-- Filters slot -->
15
- <slot name="filters" />
16
-
17
- <!-- Loading state -->
18
- <div v-if="loading" class="cn-loading-container">
19
- <NcLoadingIcon :size="32" />
20
- </div>
21
-
22
- <!-- Main content (table area) -->
23
- <template v-else>
24
- <slot />
25
- </template>
26
-
27
- <!-- Pagination slot -->
28
- <slot name="pagination" />
29
- </div>
30
- </template>
31
-
32
- <script>
33
- import { NcLoadingIcon } from '@nextcloud/vue'
34
-
35
- /**
36
- * CnListViewLayout — Full list page layout wrapping header, filters, table, and pagination.
37
- *
38
- * Provides the standard page structure used by every list view: a header with
39
- * title + action buttons, a filter/search area, the main content (table), and pagination.
40
- *
41
- * @example
42
- * <CnListViewLayout title="Clients" :total-items="clients.length" :loading="isLoading">
43
- * <template #actions>
44
- * <NcButton type="primary" @click="createClient">New client</NcButton>
45
- * </template>
46
- * <template #filters>
47
- * <CnFilterBar ... />
48
- * </template>
49
- * <CnDataTable :columns="columns" :rows="clients" />
50
- * <template #pagination>
51
- * <CnPagination ... />
52
- * </template>
53
- * </CnListViewLayout>
54
- */
55
- export default {
56
- name: 'CnListViewLayout',
57
-
58
- components: {
59
- NcLoadingIcon,
60
- },
61
-
62
- props: {
63
- /** Page title */
64
- title: {
65
- type: String,
66
- required: true,
67
- },
68
- /** Total items count (shown next to title) */
69
- totalItems: {
70
- type: Number,
71
- default: 0,
72
- },
73
- /** Whether data is loading */
74
- loading: {
75
- type: Boolean,
76
- default: false,
77
- },
78
- },
79
- }
80
- </script>
@@ -1 +0,0 @@
1
- export { default as CnListViewLayout } from './CnListViewLayout.vue'
@@ -1,77 +0,0 @@
1
- <template>
2
- <div class="cn-view-mode-toggle" role="group" :aria-label="ariaLabel">
3
- <NcButton
4
- :type="value === 'cards' ? 'primary' : 'secondary'"
5
- :aria-pressed="String(value === 'cards')"
6
- @click="$emit('input', 'cards')">
7
- <template #icon>
8
- <ViewGrid :size="20" />
9
- </template>
10
- {{ cardsLabel }}
11
- </NcButton>
12
- <NcButton
13
- :type="value === 'table' ? 'primary' : 'secondary'"
14
- :aria-pressed="String(value === 'table')"
15
- @click="$emit('input', 'table')">
16
- <template #icon>
17
- <ViewList :size="20" />
18
- </template>
19
- {{ tableLabel }}
20
- </NcButton>
21
- </div>
22
- </template>
23
-
24
- <script>
25
- import { NcButton } from '@nextcloud/vue'
26
- import ViewGrid from 'vue-material-design-icons/ViewGrid.vue'
27
- import ViewList from 'vue-material-design-icons/ViewList.vue'
28
-
29
- /**
30
- * CnViewModeToggle — Cards/Table view mode toggle.
31
- *
32
- * @example
33
- * <CnViewModeToggle v-model="viewMode" />
34
- */
35
- export default {
36
- name: 'CnViewModeToggle',
37
-
38
- components: {
39
- NcButton,
40
- ViewGrid,
41
- ViewList,
42
- },
43
-
44
- props: {
45
- /** Current view mode: 'cards' or 'table' */
46
- value: {
47
- type: String,
48
- default: 'table',
49
- validator: (v) => ['cards', 'table'].includes(v),
50
- },
51
- /** Label for cards button */
52
- cardsLabel: {
53
- type: String,
54
- default: 'Cards',
55
- },
56
- /** Label for table button */
57
- tableLabel: {
58
- type: String,
59
- default: 'Table',
60
- },
61
- /** Aria label for the toggle group */
62
- ariaLabel: {
63
- type: String,
64
- default: 'View mode',
65
- },
66
- },
67
- }
68
- </script>
69
-
70
- <style scoped>
71
- .cn-view-mode-toggle {
72
- display: inline-flex;
73
- gap: 0;
74
- border-radius: var(--border-radius-pill, 20px);
75
- overflow: hidden;
76
- }
77
- </style>
@@ -1 +0,0 @@
1
- export { default as CnViewModeToggle } from './CnViewModeToggle.vue'