@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,180 @@
1
+ <!--
2
+ CnWidgetRenderer — Renders Nextcloud Dashboard API widgets (v1/v2).
3
+
4
+ Loads widget items from the Nextcloud widget API and displays them
5
+ using NcDashboardWidget. Supports auto-refresh for widgets that
6
+ define a reload interval.
7
+ -->
8
+ <template>
9
+ <div class="cn-widget-renderer">
10
+ <!-- API Widget V1 or V2 -->
11
+ <NcDashboardWidget
12
+ v-if="isApiWidget"
13
+ :items="widgetItems"
14
+ :show-more-url="widget.widgetUrl"
15
+ :loading="loading"
16
+ :item-menu="false"
17
+ :round-icons="widget.itemIconsRound">
18
+ <template #empty-content>
19
+ <NcEmptyContent
20
+ v-if="emptyMessage"
21
+ :description="emptyMessage">
22
+ <template #icon>
23
+ <span v-if="widget.iconClass" :class="widget.iconClass" />
24
+ </template>
25
+ </NcEmptyContent>
26
+ </template>
27
+ </NcDashboardWidget>
28
+
29
+ <!-- Loading state -->
30
+ <div v-else-if="loading" class="cn-widget-renderer__loading">
31
+ <NcLoadingIcon :size="32" />
32
+ </div>
33
+
34
+ <!-- Fallback for unknown widget types -->
35
+ <NcEmptyContent
36
+ v-else
37
+ :description="unavailableText">
38
+ <template #icon>
39
+ <AlertCircleOutline :size="48" />
40
+ </template>
41
+ </NcEmptyContent>
42
+ </div>
43
+ </template>
44
+
45
+ <script>
46
+ import { NcDashboardWidget, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue'
47
+ import AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'
48
+ import axios from '@nextcloud/axios'
49
+ import { generateOcsUrl } from '@nextcloud/router'
50
+
51
+ /**
52
+ * CnWidgetRenderer — Renders Nextcloud Dashboard API widgets.
53
+ *
54
+ * Fetches widget items from the OCS Dashboard API and displays them
55
+ * using the standard NcDashboardWidget component.
56
+ *
57
+ * @example
58
+ * <CnWidgetRenderer :widget="ncWidget" />
59
+ */
60
+ export default {
61
+ name: 'CnWidgetRenderer',
62
+
63
+ components: {
64
+ NcDashboardWidget,
65
+ NcEmptyContent,
66
+ NcLoadingIcon,
67
+ AlertCircleOutline,
68
+ },
69
+
70
+ props: {
71
+ /**
72
+ * Nextcloud widget object from the Dashboard API.
73
+ * @type {{ id: string, title: string, iconClass?: string, iconUrl?: string, widgetUrl?: string, itemIconsRound?: boolean, itemApiVersions?: number[], reloadInterval?: number, buttons?: Array }}
74
+ */
75
+ widget: {
76
+ type: Object,
77
+ required: true,
78
+ },
79
+ /** Text shown when widget is not available */
80
+ unavailableText: {
81
+ type: String,
82
+ default: 'Widget not available',
83
+ },
84
+ },
85
+
86
+ data() {
87
+ return {
88
+ loading: false,
89
+ items: [],
90
+ emptyMessage: '',
91
+ refreshInterval: null,
92
+ }
93
+ },
94
+
95
+ computed: {
96
+ isApiWidgetV2() {
97
+ return this.widget?.itemApiVersions?.includes(2)
98
+ },
99
+
100
+ isApiWidgetV1() {
101
+ return this.widget?.itemApiVersions?.includes(1)
102
+ },
103
+
104
+ isApiWidget() {
105
+ return this.isApiWidgetV1 || this.isApiWidgetV2
106
+ },
107
+
108
+ widgetItems() {
109
+ return this.items.map(item => ({
110
+ id: item.sinceId || item.id || String(Math.random()),
111
+ targetUrl: item.link || item.targetUrl || '',
112
+ avatarUrl: item.iconUrl || item.avatarUrl || '',
113
+ avatarUsername: item.avatarUsername || '',
114
+ overlayIconUrl: item.overlayIconUrl || '',
115
+ mainText: item.title || item.mainText || '',
116
+ subText: item.subtitle || item.subText || '',
117
+ }))
118
+ },
119
+ },
120
+
121
+ async mounted() {
122
+ if (this.isApiWidget) {
123
+ await this.loadItems()
124
+
125
+ if (this.widget.reloadInterval && this.widget.reloadInterval > 0) {
126
+ this.refreshInterval = setInterval(
127
+ () => this.loadItems(),
128
+ this.widget.reloadInterval * 1000,
129
+ )
130
+ }
131
+ }
132
+ },
133
+
134
+ beforeDestroy() {
135
+ if (this.refreshInterval) {
136
+ clearInterval(this.refreshInterval)
137
+ }
138
+ },
139
+
140
+ methods: {
141
+ async loadItems() {
142
+ this.loading = true
143
+ try {
144
+ const version = this.isApiWidgetV2 ? 2 : 1
145
+ const url = generateOcsUrl(
146
+ `/apps/dashboard/api/v${version}/widget-items`,
147
+ )
148
+ const response = await axios.get(url, {
149
+ params: { widgets: [this.widget.id] },
150
+ })
151
+
152
+ const data = response.data?.ocs?.data
153
+ if (data && data[this.widget.id]) {
154
+ const widgetData = data[this.widget.id]
155
+ this.items = widgetData.items || widgetData || []
156
+ this.emptyMessage = widgetData.emptyContentMessage || ''
157
+ }
158
+ } catch (error) {
159
+ console.error(`[CnWidgetRenderer] Failed to load items for ${this.widget.id}:`, error)
160
+ } finally {
161
+ this.loading = false
162
+ }
163
+ },
164
+ },
165
+ }
166
+ </script>
167
+
168
+ <style scoped>
169
+ .cn-widget-renderer {
170
+ height: 100%;
171
+ padding: 8px;
172
+ }
173
+
174
+ .cn-widget-renderer__loading {
175
+ display: flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ height: 100%;
179
+ }
180
+ </style>
@@ -0,0 +1 @@
1
+ export { default as CnWidgetRenderer } from './CnWidgetRenderer.vue'
@@ -0,0 +1,248 @@
1
+ <!--
2
+ CnWidgetWrapper — Container shell around a dashboard widget.
3
+
4
+ Provides header (icon + title), scrollable content area, and optional
5
+ footer with action buttons. Applies style configuration for borders,
6
+ backgrounds, and padding.
7
+ -->
8
+ <template>
9
+ <div
10
+ class="cn-widget-wrapper"
11
+ :class="{
12
+ 'cn-widget-wrapper--borderless': borderless,
13
+ 'cn-widget-wrapper--flush': flush,
14
+ }"
15
+ :style="wrapperStyles">
16
+ <!-- Header -->
17
+ <div v-if="showTitle" class="cn-widget-wrapper__header">
18
+ <div class="cn-widget-wrapper__header-left">
19
+ <img
20
+ v-if="iconUrl"
21
+ :src="iconUrl"
22
+ :alt="displayTitle"
23
+ class="cn-widget-wrapper__icon">
24
+ <span
25
+ v-else-if="iconClass"
26
+ :class="iconClass"
27
+ class="cn-widget-wrapper__icon" />
28
+ <h3 class="cn-widget-wrapper__title">
29
+ {{ displayTitle }}
30
+ </h3>
31
+ </div>
32
+ <div class="cn-widget-wrapper__actions">
33
+ <slot name="actions" />
34
+ </div>
35
+ </div>
36
+
37
+ <!-- Content -->
38
+ <div class="cn-widget-wrapper__content">
39
+ <slot />
40
+ </div>
41
+
42
+ <!-- Footer -->
43
+ <div v-if="$slots.footer || (buttons && buttons.length > 0)" class="cn-widget-wrapper__footer">
44
+ <slot name="footer">
45
+ <a
46
+ v-for="button in buttons"
47
+ :key="button.link"
48
+ :href="button.link"
49
+ class="cn-widget-wrapper__footer-link">
50
+ {{ button.text }}
51
+ </a>
52
+ </slot>
53
+ </div>
54
+ </div>
55
+ </template>
56
+
57
+ <script>
58
+ import { translate as t } from '@nextcloud/l10n'
59
+
60
+ /**
61
+ * CnWidgetWrapper — Widget container with header, content, and footer.
62
+ *
63
+ * @example
64
+ * <CnWidgetWrapper title="My Cases" :icon-url="casesIconUrl">
65
+ * <MyCasesChart :data="chartData" />
66
+ * </CnWidgetWrapper>
67
+ *
68
+ * @example With NC widget object
69
+ * <CnWidgetWrapper
70
+ * :title="widget.title"
71
+ * :icon-url="widget.iconUrl"
72
+ * :icon-class="widget.iconClass"
73
+ * :buttons="widget.buttons">
74
+ * <CnWidgetRenderer :widget="widget" />
75
+ * </CnWidgetWrapper>
76
+ */
77
+ export default {
78
+ name: 'CnWidgetWrapper',
79
+
80
+ props: {
81
+ /** Widget title */
82
+ title: {
83
+ type: String,
84
+ default: () => t('nextcloud-vue', 'Widget'),
85
+ },
86
+ /** Whether to show the header with title */
87
+ showTitle: {
88
+ type: Boolean,
89
+ default: true,
90
+ },
91
+ /**
92
+ * Remove border and background — makes the wrapper transparent.
93
+ * Useful for widgets that are self-contained cards (e.g. CnStatsBlock).
94
+ */
95
+ borderless: {
96
+ type: Boolean,
97
+ default: false,
98
+ },
99
+ /**
100
+ * Remove content padding — allows content to go edge-to-edge.
101
+ * Useful for list-style widgets where items should span the full width.
102
+ */
103
+ flush: {
104
+ type: Boolean,
105
+ default: false,
106
+ },
107
+ /** Icon URL (image) */
108
+ iconUrl: {
109
+ type: String,
110
+ default: null,
111
+ },
112
+ /** Icon CSS class (e.g., Nextcloud icon class) */
113
+ iconClass: {
114
+ type: String,
115
+ default: null,
116
+ },
117
+ /** Footer action buttons: [{ text, link }] */
118
+ buttons: {
119
+ type: Array,
120
+ default: () => [],
121
+ },
122
+ /**
123
+ * Style configuration for the wrapper.
124
+ * @type {{ backgroundColor?: string, borderStyle?: string, borderWidth?: number, borderColor?: string, borderRadius?: number, padding?: { top: number, right: number, bottom: number, left: number } }}
125
+ */
126
+ styleConfig: {
127
+ type: Object,
128
+ default: () => ({}),
129
+ },
130
+ },
131
+
132
+ computed: {
133
+ displayTitle() {
134
+ return this.title || 'Widget'
135
+ },
136
+
137
+ wrapperStyles() {
138
+ const styles = {}
139
+
140
+ if (this.styleConfig.backgroundColor) {
141
+ styles.backgroundColor = this.styleConfig.backgroundColor
142
+ }
143
+
144
+ if (this.styleConfig.borderStyle && this.styleConfig.borderStyle !== 'none') {
145
+ styles.border = `${this.styleConfig.borderWidth || 1}px ${this.styleConfig.borderStyle} ${this.styleConfig.borderColor || 'var(--color-border)'}`
146
+ }
147
+
148
+ if (this.styleConfig.borderRadius !== undefined) {
149
+ styles.borderRadius = `${this.styleConfig.borderRadius}px`
150
+ }
151
+
152
+ if (this.styleConfig.padding) {
153
+ const p = this.styleConfig.padding
154
+ styles.padding = `${p.top || 0}px ${p.right || 0}px ${p.bottom || 0}px ${p.left || 0}px`
155
+ }
156
+
157
+ return styles
158
+ },
159
+ },
160
+ }
161
+ </script>
162
+
163
+ <style scoped>
164
+ .cn-widget-wrapper {
165
+ height: 100%;
166
+ display: flex;
167
+ flex-direction: column;
168
+ background: var(--color-main-background);
169
+ border: 1px solid var(--color-border);
170
+ overflow: hidden;
171
+ }
172
+
173
+ .cn-widget-wrapper--borderless {
174
+ border: none;
175
+ background: transparent;
176
+ }
177
+
178
+ .cn-widget-wrapper--borderless .cn-widget-wrapper__content {
179
+ padding: 0;
180
+ }
181
+
182
+ .cn-widget-wrapper--flush .cn-widget-wrapper__content {
183
+ padding: 0;
184
+ }
185
+
186
+ .cn-widget-wrapper__header {
187
+ display: flex;
188
+ align-items: center;
189
+ justify-content: space-between;
190
+ padding: 12px 16px;
191
+ border-bottom: 1px solid var(--color-border);
192
+ flex-shrink: 0;
193
+ }
194
+
195
+ .cn-widget-wrapper__header-left {
196
+ display: flex;
197
+ align-items: center;
198
+ gap: 8px;
199
+ min-width: 0;
200
+ }
201
+
202
+ .cn-widget-wrapper__icon {
203
+ width: 24px;
204
+ height: 24px;
205
+ flex-shrink: 0;
206
+ }
207
+
208
+ .cn-widget-wrapper__title {
209
+ font-weight: 600;
210
+ font-size: 14px;
211
+ margin: 0;
212
+ white-space: nowrap;
213
+ overflow: hidden;
214
+ text-overflow: ellipsis;
215
+ }
216
+
217
+ .cn-widget-wrapper__content {
218
+ flex: 1;
219
+ overflow: auto;
220
+ min-height: 0;
221
+ padding: 16px;
222
+ }
223
+
224
+ .cn-widget-wrapper__actions {
225
+ display: flex;
226
+ gap: 4px;
227
+ flex-shrink: 0;
228
+ }
229
+
230
+ .cn-widget-wrapper__footer {
231
+ display: flex;
232
+ justify-content: flex-end;
233
+ gap: 8px;
234
+ padding: 8px 16px;
235
+ border-top: 1px solid var(--color-border);
236
+ flex-shrink: 0;
237
+ }
238
+
239
+ .cn-widget-wrapper__footer-link {
240
+ font-size: 13px;
241
+ color: var(--color-primary-element);
242
+ text-decoration: none;
243
+ }
244
+
245
+ .cn-widget-wrapper__footer-link:hover {
246
+ text-decoration: underline;
247
+ }
248
+ </style>
@@ -0,0 +1 @@
1
+ export { default as CnWidgetWrapper } from './CnWidgetWrapper.vue'
@@ -1,25 +1,57 @@
1
- export { CnDataTable } from './CnDataTable/index.js'
2
- export { CnFilterBar } from './CnFilterBar/index.js'
3
- export { CnListViewLayout } from './CnListViewLayout/index.js'
4
- export { CnDetailViewLayout } from './CnDetailViewLayout/index.js'
5
- export { CnStatusBadge } from './CnStatusBadge/index.js'
6
- export { CnEmptyState } from './CnEmptyState/index.js'
7
- export { CnPagination } from './CnPagination/index.js'
8
- export { CnSettingsCard } from './CnSettingsCard/index.js'
9
- export { CnSettingsSection } from './CnSettingsSection/index.js'
10
- export { CnStatsBlock } from './CnStatsBlock/index.js'
11
- export { CnConfigurationCard } from './CnConfigurationCard/index.js'
12
- export { CnVersionInfoCard } from './CnVersionInfoCard/index.js'
13
- export { CnCellRenderer } from './CnCellRenderer/index.js'
14
- export { CnObjectCard } from './CnObjectCard/index.js'
15
- export { CnCardGrid } from './CnCardGrid/index.js'
16
- export { CnFacetSidebar } from './CnFacetSidebar/index.js'
17
- export { CnViewModeToggle } from './CnViewModeToggle/index.js'
18
- export { CnRowActions } from './CnRowActions/index.js'
19
- export { CnIndexPage } from './CnIndexPage/index.js'
20
- export { CnMassActionBar } from './CnMassActionBar/index.js'
21
- export { CnMassDeleteDialog } from './CnMassDeleteDialog/index.js'
22
- export { CnMassCopyDialog } from './CnMassCopyDialog/index.js'
23
- export { CnKpiGrid } from './CnKpiGrid/index.js'
24
- export { CnMassExportDialog } from './CnMassExportDialog/index.js'
25
- export { CnMassImportDialog } from './CnMassImportDialog/index.js'
1
+ export { CnDataTable } from './CnDataTable/index.js'
2
+ export { CnFilterBar } from './CnFilterBar/index.js'
3
+ export { CnStatusBadge } from './CnStatusBadge/index.js'
4
+ export { CnPagination } from './CnPagination/index.js'
5
+ export { CnSettingsCard } from './CnSettingsCard/index.js'
6
+ export { CnSettingsSection } from './CnSettingsSection/index.js'
7
+ export { CnStatsBlock } from './CnStatsBlock/index.js'
8
+ export { CnConfigurationCard } from './CnConfigurationCard/index.js'
9
+ export { CnVersionInfoCard } from './CnVersionInfoCard/index.js'
10
+ export { CnCellRenderer } from './CnCellRenderer/index.js'
11
+ export { CnObjectCard } from './CnObjectCard/index.js'
12
+ export { CnCardGrid } from './CnCardGrid/index.js'
13
+ export { CnFacetSidebar } from './CnFacetSidebar/index.js'
14
+ export { CnRowActions } from './CnRowActions/index.js'
15
+ export { CnContextMenu } from './CnContextMenu/index.js'
16
+ export { CnIndexPage } from './CnIndexPage/index.js'
17
+ export { CnMassActionBar } from './CnMassActionBar/index.js'
18
+ export { CnDeleteDialog } from './CnDeleteDialog/index.js'
19
+ export { CnCopyDialog } from './CnCopyDialog/index.js'
20
+ export { CnFormDialog } from './CnFormDialog/index.js'
21
+ export { CnAdvancedFormDialog } from './CnAdvancedFormDialog/index.js'
22
+ export { CnMassDeleteDialog } from './CnMassDeleteDialog/index.js'
23
+ export { CnMassCopyDialog } from './CnMassCopyDialog/index.js'
24
+ export { CnKpiGrid } from './CnKpiGrid/index.js'
25
+ export { CnMassExportDialog } from './CnMassExportDialog/index.js'
26
+ export { CnMassImportDialog } from './CnMassImportDialog/index.js'
27
+ export { CnIndexSidebar } from './CnIndexSidebar/index.js'
28
+ export { CnRegisterMapping } from './CnRegisterMapping/index.js'
29
+ export { CnIcon, ICON_MAP, registerIcons } from './CnIcon/index.js'
30
+ export { CnPageHeader } from './CnPageHeader/index.js'
31
+ export { CnActionsBar } from './CnActionsBar/index.js'
32
+ export { CnDetailPage } from './CnDetailPage/index.js'
33
+ export { CnDashboardPage } from './CnDashboardPage/index.js'
34
+ export { CnDashboardGrid } from './CnDashboardGrid/index.js'
35
+ export { CnWidgetWrapper } from './CnWidgetWrapper/index.js'
36
+ export { CnWidgetRenderer } from './CnWidgetRenderer/index.js'
37
+ export { CnTileWidget } from './CnTileWidget/index.js'
38
+ export { CnItemCard } from './CnItemCard/index.js'
39
+ export { CnSchemaFormDialog } from './CnSchemaFormDialog/index.js'
40
+ export { CnTabbedFormDialog } from './CnTabbedFormDialog/index.js'
41
+ export { CnTimelineStages } from './CnTimelineStages/index.js'
42
+ export { CnUserActionMenu } from './CnUserActionMenu/index.js'
43
+ export { CnNotesCard } from './CnNotesCard/index.js'
44
+ export { CnTasksCard } from './CnTasksCard/index.js'
45
+ export { CnDetailCard } from './CnDetailCard/index.js'
46
+ export { CnCard } from './CnCard/index.js'
47
+ export { CnStatsPanel } from './CnStatsPanel/index.js'
48
+ export { CnJsonViewer } from './CnJsonViewer/index.js'
49
+ export { CnDetailGrid } from './CnDetailGrid/index.js'
50
+ export { CnProgressBar } from './CnProgressBar/index.js'
51
+ export { CnChartWidget } from './CnChartWidget/index.js'
52
+ export { CnObjectSidebar } from './CnObjectSidebar/index.js'
53
+ export { CnInfoWidget } from './CnInfoWidget/index.js'
54
+ export { CnTableWidget } from './CnTableWidget/index.js'
55
+ export { CnNoteCard } from './CnNoteCard/index.js'
56
+ export { CnObjectDataWidget } from './CnObjectDataWidget/index.js'
57
+ export { CnObjectMetadataWidget } from './CnObjectMetadataWidget/index.js'
@@ -1,3 +1,5 @@
1
- export { useListView } from './useListView.js'
2
- export { useDetailView } from './useDetailView.js'
3
- export { useSubResource } from './useSubResource.js'
1
+ export { useListView } from './useListView.js'
2
+ export { useDetailView } from './useDetailView.js'
3
+ export { useSubResource } from './useSubResource.js'
4
+ export { useDashboardView } from './useDashboardView.js'
5
+ export { useContextMenu } from './useContextMenu.js'
@@ -0,0 +1,126 @@
1
+ import { ref, onBeforeUnmount } from 'vue'
2
+
3
+ const CSS_VAR_X = '--cn-ctx-menu-x'
4
+ const CSS_VAR_Y = '--cn-ctx-menu-y'
5
+ const DATA_ATTR = 'data-cn-ctx-menu'
6
+
7
+ /**
8
+ * Composable for managing a right-click context menu positioned at the cursor.
9
+ *
10
+ * Handles cursor-based positioning through CSS custom properties and a data
11
+ * attribute on `document.documentElement`. The `<NcActions>` template stays in
12
+ * the consuming component — this composable only manages open/close state,
13
+ * the target item reference, and action helpers.
14
+ *
15
+ * Pair with the shared CSS in `src/css/context-menu.css` (auto-imported via
16
+ * `src/css/index.css`) which overrides `.v-popper__popper` transforms when
17
+ * the data attribute is present.
18
+ *
19
+ * @example In a Vue Options API component with setup()
20
+ * ```js
21
+ * import { useContextMenu } from '@conduction/nextcloud-vue'
22
+ *
23
+ * export default {
24
+ * setup() {
25
+ * const ctx = useContextMenu()
26
+ * return {
27
+ * contextMenuOpen: ctx.isOpen,
28
+ * contextMenuRow: ctx.targetItem,
29
+ * openContextMenu: ctx.open,
30
+ * closeContextMenu: ctx.close,
31
+ * isContextActionDisabled: ctx.isActionDisabled,
32
+ * triggerContextAction: ctx.triggerAction,
33
+ * }
34
+ * },
35
+ * }
36
+ * ```
37
+ *
38
+ * @return {{
39
+ * isOpen: import('vue').Ref<boolean>,
40
+ * targetItem: import('vue').Ref<any>,
41
+ * open: (params: { item: any, event: MouseEvent }) => void,
42
+ * close: () => void,
43
+ * isActionDisabled: (action: { disabled?: boolean | ((item: any) => boolean) }) => boolean,
44
+ * triggerAction: (action: { label: string, handler?: (item: any) => void }) => { action: string, row: any },
45
+ * }}
46
+ */
47
+ export function useContextMenu() {
48
+ const isOpen = ref(false)
49
+ const targetItem = ref(null)
50
+
51
+ /**
52
+ * Open the context menu at the cursor position.
53
+ *
54
+ * Sets CSS custom properties for x/y coordinates and a data attribute on
55
+ * `document.documentElement` so the shared CSS can override Popper positioning.
56
+ *
57
+ * @param {object} params
58
+ * @param {any} params.item The item associated with the right-click (row, folder, etc.)
59
+ * @param {MouseEvent} params.event The native contextmenu event
60
+ */
61
+ function open({ item, event }) {
62
+ document.documentElement.style.setProperty(CSS_VAR_X, event.clientX + 'px')
63
+ document.documentElement.style.setProperty(CSS_VAR_Y, event.clientY + 'px')
64
+ document.documentElement.setAttribute(DATA_ATTR, '')
65
+ targetItem.value = item
66
+ isOpen.value = true
67
+ }
68
+
69
+ /**
70
+ * Close the context menu and clean up DOM attributes.
71
+ * Use as the `@close` handler on `<NcActions>`.
72
+ */
73
+ function close() {
74
+ isOpen.value = false
75
+ document.documentElement.style.removeProperty(CSS_VAR_X)
76
+ document.documentElement.style.removeProperty(CSS_VAR_Y)
77
+ document.documentElement.removeAttribute(DATA_ATTR)
78
+ targetItem.value = null
79
+ }
80
+
81
+ /**
82
+ * Resolve whether an action is disabled for the current target item.
83
+ * Supports both a static boolean and a function `(item) => boolean`.
84
+ *
85
+ * @param {object} action Action definition with optional `disabled` field
86
+ * @return {boolean}
87
+ */
88
+ function isActionDisabled(action) {
89
+ if (typeof action.disabled === 'function') {
90
+ return action.disabled(targetItem.value)
91
+ }
92
+ return !!action.disabled
93
+ }
94
+
95
+ /**
96
+ * Execute a context menu action.
97
+ *
98
+ * Calls `action.handler(targetItem)` if a handler exists, then returns a
99
+ * payload object the caller can pass to `$emit('action', payload)`.
100
+ *
101
+ * @param {object} action Action definition with `label` and optional `handler`
102
+ * @return {{ action: string, row: any }}
103
+ */
104
+ function triggerAction(action) {
105
+ if (action.handler && typeof action.handler === 'function') {
106
+ action.handler(targetItem.value)
107
+ }
108
+ return { action: action.label, row: targetItem.value }
109
+ }
110
+
111
+ // Clean up DOM if the component unmounts while the menu is open
112
+ onBeforeUnmount(() => {
113
+ if (isOpen.value) {
114
+ close()
115
+ }
116
+ })
117
+
118
+ return {
119
+ isOpen,
120
+ targetItem,
121
+ open,
122
+ close,
123
+ isActionDisabled,
124
+ triggerAction,
125
+ }
126
+ }