@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
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="cn-schema-form__security-section">
|
|
3
|
+
<CnNoteCard type="info">
|
|
4
|
+
<p><strong>Role-Based Access Control (RBAC)</strong></p>
|
|
5
|
+
<p>Configure which Nextcloud user groups can perform CRUD operations on objects of this schema.</p>
|
|
6
|
+
<ul>
|
|
7
|
+
<li>If no groups are specified for an operation, all users can perform it</li>
|
|
8
|
+
<li>The 'admin' group always has full access (cannot be changed)</li>
|
|
9
|
+
<li>The object owner always has full access</li>
|
|
10
|
+
<li>'public' represents unauthenticated access</li>
|
|
11
|
+
</ul>
|
|
12
|
+
</CnNoteCard>
|
|
13
|
+
|
|
14
|
+
<div v-if="loadingGroups" class="cn-schema-form__loading-groups">
|
|
15
|
+
<NcLoadingIcon :size="20" />
|
|
16
|
+
<span>Loading user groups...</span>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div v-else class="cn-schema-form__rbac-table-container">
|
|
20
|
+
<h3>Group Permissions</h3>
|
|
21
|
+
<table class="cn-schema-form__rbac-table">
|
|
22
|
+
<thead>
|
|
23
|
+
<tr>
|
|
24
|
+
<th>Group</th>
|
|
25
|
+
<th>Create</th>
|
|
26
|
+
<th>Read</th>
|
|
27
|
+
<th>Update</th>
|
|
28
|
+
<th>Delete</th>
|
|
29
|
+
</tr>
|
|
30
|
+
</thead>
|
|
31
|
+
<tbody>
|
|
32
|
+
<!-- Public group at top -->
|
|
33
|
+
<tr class="cn-schema-form__public-row">
|
|
34
|
+
<td class="cn-schema-form__group-name">
|
|
35
|
+
<span class="cn-schema-form__group-badge cn-schema-form__public">public</span>
|
|
36
|
+
<small>Unauthenticated users</small>
|
|
37
|
+
</td>
|
|
38
|
+
<td>
|
|
39
|
+
<NcCheckboxRadioSwitch
|
|
40
|
+
:checked="hasGroupPermission('public', 'create')"
|
|
41
|
+
@update:checked="updateGroupPermission('public', 'create', $event)" />
|
|
42
|
+
</td>
|
|
43
|
+
<td>
|
|
44
|
+
<NcCheckboxRadioSwitch
|
|
45
|
+
:checked="hasGroupPermission('public', 'read')"
|
|
46
|
+
@update:checked="updateGroupPermission('public', 'read', $event)" />
|
|
47
|
+
</td>
|
|
48
|
+
<td>
|
|
49
|
+
<NcCheckboxRadioSwitch
|
|
50
|
+
:checked="hasGroupPermission('public', 'update')"
|
|
51
|
+
@update:checked="updateGroupPermission('public', 'update', $event)" />
|
|
52
|
+
</td>
|
|
53
|
+
<td>
|
|
54
|
+
<NcCheckboxRadioSwitch
|
|
55
|
+
:checked="hasGroupPermission('public', 'delete')"
|
|
56
|
+
@update:checked="updateGroupPermission('public', 'delete', $event)" />
|
|
57
|
+
</td>
|
|
58
|
+
</tr>
|
|
59
|
+
|
|
60
|
+
<!-- User group (authenticated users) -->
|
|
61
|
+
<tr class="cn-schema-form__user-row">
|
|
62
|
+
<td class="cn-schema-form__group-name">
|
|
63
|
+
<span class="cn-schema-form__group-badge cn-schema-form__user">user</span>
|
|
64
|
+
<small>Authenticated users</small>
|
|
65
|
+
</td>
|
|
66
|
+
<td>
|
|
67
|
+
<NcCheckboxRadioSwitch
|
|
68
|
+
:checked="hasGroupPermission('user', 'create')"
|
|
69
|
+
@update:checked="updateGroupPermission('user', 'create', $event)" />
|
|
70
|
+
</td>
|
|
71
|
+
<td>
|
|
72
|
+
<NcCheckboxRadioSwitch
|
|
73
|
+
:checked="hasGroupPermission('user', 'read')"
|
|
74
|
+
@update:checked="updateGroupPermission('user', 'read', $event)" />
|
|
75
|
+
</td>
|
|
76
|
+
<td>
|
|
77
|
+
<NcCheckboxRadioSwitch
|
|
78
|
+
:checked="hasGroupPermission('user', 'update')"
|
|
79
|
+
@update:checked="updateGroupPermission('user', 'update', $event)" />
|
|
80
|
+
</td>
|
|
81
|
+
<td>
|
|
82
|
+
<NcCheckboxRadioSwitch
|
|
83
|
+
:checked="hasGroupPermission('user', 'delete')"
|
|
84
|
+
@update:checked="updateGroupPermission('user', 'delete', $event)" />
|
|
85
|
+
</td>
|
|
86
|
+
</tr>
|
|
87
|
+
|
|
88
|
+
<!-- Regular user groups -->
|
|
89
|
+
<tr v-for="group in sortedUserGroups" :key="group.id">
|
|
90
|
+
<td class="cn-schema-form__group-name">
|
|
91
|
+
<span class="cn-schema-form__group-badge">{{ group.displayname || group.id }}</span>
|
|
92
|
+
<small v-if="group.displayname && group.displayname !== group.id">{{ group.id }}</small>
|
|
93
|
+
</td>
|
|
94
|
+
<td>
|
|
95
|
+
<NcCheckboxRadioSwitch
|
|
96
|
+
:checked="hasGroupPermission(group.id, 'create')"
|
|
97
|
+
@update:checked="updateGroupPermission(group.id, 'create', $event)" />
|
|
98
|
+
</td>
|
|
99
|
+
<td>
|
|
100
|
+
<NcCheckboxRadioSwitch
|
|
101
|
+
:checked="hasGroupPermission(group.id, 'read')"
|
|
102
|
+
@update:checked="updateGroupPermission(group.id, 'read', $event)" />
|
|
103
|
+
</td>
|
|
104
|
+
<td>
|
|
105
|
+
<NcCheckboxRadioSwitch
|
|
106
|
+
:checked="hasGroupPermission(group.id, 'update')"
|
|
107
|
+
@update:checked="updateGroupPermission(group.id, 'update', $event)" />
|
|
108
|
+
</td>
|
|
109
|
+
<td>
|
|
110
|
+
<NcCheckboxRadioSwitch
|
|
111
|
+
:checked="hasGroupPermission(group.id, 'delete')"
|
|
112
|
+
@update:checked="updateGroupPermission(group.id, 'delete', $event)" />
|
|
113
|
+
</td>
|
|
114
|
+
</tr>
|
|
115
|
+
|
|
116
|
+
<!-- Admin group at bottom (disabled) -->
|
|
117
|
+
<tr class="cn-schema-form__admin-row">
|
|
118
|
+
<td class="cn-schema-form__group-name">
|
|
119
|
+
<span class="cn-schema-form__group-badge cn-schema-form__admin">admin</span>
|
|
120
|
+
<small>Always has full access</small>
|
|
121
|
+
</td>
|
|
122
|
+
<td>
|
|
123
|
+
<NcCheckboxRadioSwitch
|
|
124
|
+
:checked="true"
|
|
125
|
+
:disabled="true" />
|
|
126
|
+
</td>
|
|
127
|
+
<td>
|
|
128
|
+
<NcCheckboxRadioSwitch
|
|
129
|
+
:checked="true"
|
|
130
|
+
:disabled="true" />
|
|
131
|
+
</td>
|
|
132
|
+
<td>
|
|
133
|
+
<NcCheckboxRadioSwitch
|
|
134
|
+
:checked="true"
|
|
135
|
+
:disabled="true" />
|
|
136
|
+
</td>
|
|
137
|
+
<td>
|
|
138
|
+
<NcCheckboxRadioSwitch
|
|
139
|
+
:checked="true"
|
|
140
|
+
:disabled="true" />
|
|
141
|
+
</td>
|
|
142
|
+
</tr>
|
|
143
|
+
</tbody>
|
|
144
|
+
</table>
|
|
145
|
+
|
|
146
|
+
<div class="cn-schema-form__rbac-summary">
|
|
147
|
+
<CnNoteCard v-if="!hasAnyPermissions" type="success">
|
|
148
|
+
<p><strong>Open Access:</strong> No specific permissions set - all users can perform all operations.</p>
|
|
149
|
+
</CnNoteCard>
|
|
150
|
+
<CnNoteCard v-else-if="isRestrictiveSchema" type="warning">
|
|
151
|
+
<p><strong>Restrictive Schema:</strong> Access is limited to specified groups only.</p>
|
|
152
|
+
</CnNoteCard>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</template>
|
|
157
|
+
|
|
158
|
+
<script>
|
|
159
|
+
import {
|
|
160
|
+
// NcNoteCard,
|
|
161
|
+
NcCheckboxRadioSwitch,
|
|
162
|
+
NcLoadingIcon,
|
|
163
|
+
} from '@nextcloud/vue'
|
|
164
|
+
import CnNoteCard from '../CnNoteCard/CnNoteCard.vue'
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* CnSchemaSecurityTab — RBAC permissions table tab for CnSchemaFormDialog.
|
|
168
|
+
*
|
|
169
|
+
* Renders the schema-level authorization configuration. Mutates
|
|
170
|
+
* schemaItem.authorization directly.
|
|
171
|
+
*/
|
|
172
|
+
export default {
|
|
173
|
+
name: 'CnSchemaSecurityTab',
|
|
174
|
+
components: {
|
|
175
|
+
CnNoteCard,
|
|
176
|
+
NcCheckboxRadioSwitch,
|
|
177
|
+
NcLoadingIcon,
|
|
178
|
+
},
|
|
179
|
+
props: {
|
|
180
|
+
/** The full schema item — mutates authorization directly */
|
|
181
|
+
schemaItem: { type: Object, required: true },
|
|
182
|
+
/** Full user groups array */
|
|
183
|
+
userGroups: { type: Array, default: () => [] },
|
|
184
|
+
/** Filtered/sorted user groups (excludes admin/public) */
|
|
185
|
+
sortedUserGroups: { type: Array, default: () => [] },
|
|
186
|
+
/** Whether groups are loading */
|
|
187
|
+
loadingGroups: { type: Boolean, default: false },
|
|
188
|
+
/** Whether schema has any permissions set */
|
|
189
|
+
hasAnyPermissions: { type: Boolean, default: false },
|
|
190
|
+
/** Whether schema has restrictive permissions */
|
|
191
|
+
isRestrictiveSchema: { type: Boolean, default: false },
|
|
192
|
+
},
|
|
193
|
+
computed: {
|
|
194
|
+
/** Local alias to avoid vue/no-mutating-props on template bindings */
|
|
195
|
+
schema() {
|
|
196
|
+
return this.schemaItem
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
methods: {
|
|
200
|
+
hasGroupPermission(groupId, action) {
|
|
201
|
+
const auth = this.schema.authorization || {}
|
|
202
|
+
if (!auth[action] || !Array.isArray(auth[action])) {
|
|
203
|
+
return false
|
|
204
|
+
}
|
|
205
|
+
return auth[action].includes(groupId)
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
updateGroupPermission(groupId, action, hasPermission) {
|
|
209
|
+
if (!this.schema.authorization) {
|
|
210
|
+
this.$set(this.schema, 'authorization', {})
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!this.schema.authorization[action]) {
|
|
214
|
+
this.$set(this.schema.authorization, action, [])
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const currentPermissions = this.schema.authorization[action]
|
|
218
|
+
const groupIndex = currentPermissions.indexOf(groupId)
|
|
219
|
+
|
|
220
|
+
if (hasPermission && groupIndex === -1) {
|
|
221
|
+
currentPermissions.push(groupId)
|
|
222
|
+
} else if (!hasPermission && groupIndex !== -1) {
|
|
223
|
+
currentPermissions.splice(groupIndex, 1)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (currentPermissions.length === 0) {
|
|
227
|
+
this.$delete(this.schema.authorization, action)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (Object.keys(this.schema.authorization).length === 0) {
|
|
231
|
+
this.$set(this.schema, 'authorization', {})
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
}
|
|
236
|
+
</script>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as CnSchemaFormDialog } from './CnSchemaFormDialog.vue'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as CnSettingsCard } from './CnSettingsCard.vue'
|
|
1
|
+
export { default as CnSettingsCard } from './CnSettingsCard.vue'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as CnSettingsSection } from './CnSettingsSection.vue'
|
|
1
|
+
export { default as CnSettingsSection } from './CnSettingsSection.vue'
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
|
-
:is="
|
|
3
|
+
:is="componentTag"
|
|
4
4
|
class="cn-stats-block"
|
|
5
5
|
:class="rootClasses"
|
|
6
|
-
v-bind="
|
|
6
|
+
v-bind="componentAttrs"
|
|
7
7
|
@click="onClick">
|
|
8
8
|
<!-- Icon -->
|
|
9
9
|
<div v-if="hasIcon" class="cn-stats-block__icon" :class="iconClasses">
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<h4>{{ title || 'Objects' }}</h4>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
|
-
<div v-if="count > 0" class="cn-stats-block__count">
|
|
21
|
+
<div v-if="count > 0 || (showZeroCount && count === 0)" class="cn-stats-block__count">
|
|
22
22
|
<span class="cn-stats-block__count-value">{{ formattedCount }}</span>
|
|
23
23
|
<span class="cn-stats-block__count-label">{{ countLabel }}</span>
|
|
24
24
|
</div>
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
</div>
|
|
32
32
|
|
|
33
33
|
<!-- Breakdown details -->
|
|
34
|
-
<div v-if="breakdown && count > 0" class="cn-stats-block__breakdown">
|
|
34
|
+
<div v-if="breakdown && (count > 0 || showZeroCount)" class="cn-stats-block__breakdown">
|
|
35
35
|
<div
|
|
36
36
|
v-for="(value, key) in breakdown"
|
|
37
37
|
:key="key"
|
|
@@ -70,6 +70,14 @@ import { NcLoadingIcon } from '@nextcloud/vue'
|
|
|
70
70
|
* clickable
|
|
71
71
|
* @click="goToCases" />
|
|
72
72
|
*
|
|
73
|
+
* @example With route-based navigation (renders as <router-link>)
|
|
74
|
+
* <CnStatsBlock
|
|
75
|
+
* title="Open Cases"
|
|
76
|
+
* :count="42"
|
|
77
|
+
* :icon="BriefcaseOutline"
|
|
78
|
+
* variant="primary"
|
|
79
|
+
* :route="{ name: 'Cases', query: { status: 'open' } }" />
|
|
80
|
+
*
|
|
73
81
|
* @example With breakdown
|
|
74
82
|
* <CnStatsBlock
|
|
75
83
|
* title="Cases"
|
|
@@ -152,6 +160,21 @@ export default {
|
|
|
152
160
|
type: Boolean,
|
|
153
161
|
default: false,
|
|
154
162
|
},
|
|
163
|
+
/** Whether to display 0 as a count value instead of the empty label */
|
|
164
|
+
showZeroCount: {
|
|
165
|
+
type: Boolean,
|
|
166
|
+
default: false,
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* Vue Router location object for declarative navigation.
|
|
170
|
+
* When set, the card renders as a <router-link> and clickable styles are implied.
|
|
171
|
+
* @example { name: 'Cases', query: { status: 'open' } }
|
|
172
|
+
* @example { path: '/catalogi' }
|
|
173
|
+
*/
|
|
174
|
+
route: {
|
|
175
|
+
type: Object,
|
|
176
|
+
default: null,
|
|
177
|
+
},
|
|
155
178
|
},
|
|
156
179
|
|
|
157
180
|
computed: {
|
|
@@ -163,10 +186,39 @@ export default {
|
|
|
163
186
|
return this.count.toLocaleString()
|
|
164
187
|
},
|
|
165
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Whether the card is interactive (clickable or has a route).
|
|
191
|
+
* Used for applying hover/focus styles.
|
|
192
|
+
*/
|
|
193
|
+
isInteractive() {
|
|
194
|
+
return !!this.route || this.clickable
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Determines which HTML element or component to render.
|
|
199
|
+
* - route set → 'router-link' (SPA navigation)
|
|
200
|
+
* - clickable → 'a' (app handles click via event)
|
|
201
|
+
* - neither → 'div' (static display)
|
|
202
|
+
*/
|
|
203
|
+
componentTag() {
|
|
204
|
+
if (this.route) return 'router-link'
|
|
205
|
+
if (this.clickable) return 'a'
|
|
206
|
+
return 'div'
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Dynamic attributes for the root element based on rendering mode.
|
|
211
|
+
*/
|
|
212
|
+
componentAttrs() {
|
|
213
|
+
if (this.route) return { to: this.route, tabindex: '0' }
|
|
214
|
+
if (this.clickable) return { href: '#', role: 'button', tabindex: '0' }
|
|
215
|
+
return {}
|
|
216
|
+
},
|
|
217
|
+
|
|
166
218
|
rootClasses() {
|
|
167
219
|
return {
|
|
168
220
|
'cn-stats-block--horizontal': this.horizontal,
|
|
169
|
-
'cn-stats-block--clickable': this.
|
|
221
|
+
'cn-stats-block--clickable': this.isInteractive,
|
|
170
222
|
[`cn-stats-block--${this.variant}`]: this.variant !== 'default',
|
|
171
223
|
}
|
|
172
224
|
},
|
|
@@ -184,6 +236,8 @@ export default {
|
|
|
184
236
|
},
|
|
185
237
|
|
|
186
238
|
onClick(event) {
|
|
239
|
+
// When route is set, router-link handles navigation — do not emit click
|
|
240
|
+
if (this.route) return
|
|
187
241
|
if (this.clickable) {
|
|
188
242
|
event.preventDefault()
|
|
189
243
|
this.$emit('click', event)
|
|
@@ -360,7 +414,7 @@ export default {
|
|
|
360
414
|
background: var(--color-background-hover);
|
|
361
415
|
}
|
|
362
416
|
|
|
363
|
-
.cn-stats-block__breakdown-value--invalid { color: var(--color-warning); }
|
|
364
|
-
.cn-stats-block__breakdown-value--deleted { color: var(--color-error); }
|
|
365
|
-
.cn-stats-block__breakdown-value--published { color: var(--color-success); }
|
|
417
|
+
.cn-stats-block__breakdown-value--invalid { color: var(--color-element-warning); }
|
|
418
|
+
.cn-stats-block__breakdown-value--deleted { color: var(--color-element-error); }
|
|
419
|
+
.cn-stats-block__breakdown-value--published { color: var(--color-element-success); }
|
|
366
420
|
</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as CnStatsBlock } from './CnStatsBlock.vue'
|
|
1
|
+
export { default as CnStatsBlock } from './CnStatsBlock.vue'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as CnStatusBadge } from './CnStatusBadge.vue'
|
|
1
|
+
export { default as CnStatusBadge } from './CnStatusBadge.vue'
|