@conduction/nextcloud-vue 0.1.0-beta.2 → 0.1.0-beta.4

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 (153) hide show
  1. package/README.md +226 -226
  2. package/css/index.css +5 -0
  3. package/dist/nextcloud-vue.cjs.js +60455 -8755
  4. package/dist/nextcloud-vue.cjs.js.map +1 -1
  5. package/dist/nextcloud-vue.css +2062 -528
  6. package/dist/nextcloud-vue.esm.js +60411 -8731
  7. package/dist/nextcloud-vue.esm.js.map +1 -1
  8. package/package.json +75 -61
  9. package/src/components/CnActionsBar/CnActionsBar.vue +235 -225
  10. package/src/components/CnActionsBar/index.js +1 -1
  11. package/src/components/CnAdvancedFormDialog/CnAdvancedFormDialog.vue +579 -0
  12. package/src/components/CnAdvancedFormDialog/CnDataTab.vue +217 -0
  13. package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +121 -0
  14. package/src/components/CnAdvancedFormDialog/CnPropertiesTab.vue +418 -0
  15. package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +247 -0
  16. package/src/components/CnAdvancedFormDialog/index.js +1 -0
  17. package/src/components/CnCardGrid/CnCardGrid.vue +152 -152
  18. package/src/components/CnCardGrid/index.js +1 -1
  19. package/src/components/CnCellRenderer/CnCellRenderer.vue +132 -132
  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/CnConfigurationCard.vue +77 -77
  24. package/src/components/CnConfigurationCard/index.js +1 -1
  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 +349 -349
  30. package/src/components/CnDataTable/index.js +1 -1
  31. package/src/components/CnDetailCard/CnDetailCard.vue +214 -0
  32. package/src/components/CnDetailCard/index.js +1 -0
  33. package/src/components/CnDetailPage/CnDetailPage.vue +281 -0
  34. package/src/components/CnDetailPage/index.js +1 -0
  35. package/src/components/CnFacetSidebar/CnFacetSidebar.vue +231 -223
  36. package/src/components/CnFacetSidebar/index.js +1 -1
  37. package/src/components/CnFilterBar/CnFilterBar.vue +152 -152
  38. package/src/components/CnFilterBar/index.js +1 -1
  39. package/src/components/CnIcon/CnIcon.vue +89 -89
  40. package/src/components/CnIcon/index.js +1 -1
  41. package/src/components/CnIndexPage/CnIndexPage.vue +874 -816
  42. package/src/components/CnIndexPage/index.js +1 -1
  43. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +503 -484
  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/CnKpiGrid.vue +89 -89
  48. package/src/components/CnKpiGrid/index.js +1 -1
  49. package/src/components/CnMassActionBar/CnMassActionBar.vue +160 -160
  50. package/src/components/CnMassActionBar/index.js +1 -1
  51. package/src/components/CnMassCopyDialog/CnMassCopyDialog.vue +320 -320
  52. package/src/components/CnMassCopyDialog/index.js +1 -1
  53. package/src/components/CnMassDeleteDialog/CnMassDeleteDialog.vue +238 -238
  54. package/src/components/CnMassDeleteDialog/index.js +1 -1
  55. package/src/components/CnMassExportDialog/CnMassExportDialog.vue +190 -190
  56. package/src/components/CnMassExportDialog/index.js +1 -1
  57. package/src/components/CnMassImportDialog/CnMassImportDialog.vue +491 -491
  58. package/src/components/CnMassImportDialog/index.js +1 -1
  59. package/src/components/CnNoteCard/CnNoteCard.vue +149 -0
  60. package/src/components/CnNoteCard/index.js +1 -0
  61. package/src/components/CnNotesCard/CnNotesCard.vue +413 -0
  62. package/src/components/CnNotesCard/index.js +1 -0
  63. package/src/components/CnObjectCard/CnObjectCard.vue +292 -292
  64. package/src/components/CnObjectCard/index.js +1 -1
  65. package/src/components/CnObjectSidebar/CnObjectSidebar.vue +876 -0
  66. package/src/components/CnObjectSidebar/index.js +1 -0
  67. package/src/components/CnPageHeader/CnPageHeader.vue +57 -57
  68. package/src/components/CnPageHeader/index.js +1 -1
  69. package/src/components/CnPagination/CnPagination.vue +252 -252
  70. package/src/components/CnPagination/index.js +1 -1
  71. package/src/components/CnRowActions/CnRowActions.vue +73 -73
  72. package/src/components/CnRowActions/index.js +1 -1
  73. package/src/components/CnSchemaFormDialog/CnSchemaConfigurationTab.vue +226 -0
  74. package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +787 -0
  75. package/src/components/CnSchemaFormDialog/CnSchemaPropertiesTab.vue +305 -0
  76. package/src/components/CnSchemaFormDialog/CnSchemaPropertyActions.vue +1398 -0
  77. package/src/components/CnSchemaFormDialog/CnSchemaSecurityTab.vue +236 -0
  78. package/src/components/CnSchemaFormDialog/index.js +1 -0
  79. package/src/components/CnSettingsCard/CnSettingsCard.vue +92 -92
  80. package/src/components/CnSettingsCard/index.js +1 -1
  81. package/src/components/CnSettingsSection/CnSettingsSection.vue +266 -266
  82. package/src/components/CnSettingsSection/index.js +1 -1
  83. package/src/components/CnStatsBlock/CnStatsBlock.vue +420 -366
  84. package/src/components/CnStatsBlock/index.js +1 -1
  85. package/src/components/CnStatusBadge/CnStatusBadge.vue +77 -77
  86. package/src/components/CnStatusBadge/index.js +1 -1
  87. package/src/components/CnTabbedFormDialog/CnTabbedFormDialog.vue +540 -0
  88. package/src/components/CnTabbedFormDialog/index.js +1 -0
  89. package/src/components/CnTasksCard/CnTasksCard.vue +373 -0
  90. package/src/components/CnTasksCard/index.js +1 -0
  91. package/src/components/CnTileWidget/CnTileWidget.vue +159 -0
  92. package/src/components/CnTileWidget/index.js +1 -0
  93. package/src/components/CnTimelineStages/CnTimelineStages.vue +292 -0
  94. package/src/components/CnTimelineStages/index.js +1 -0
  95. package/src/components/CnUserActionMenu/CnUserActionMenu.vue +435 -0
  96. package/src/components/CnUserActionMenu/index.js +1 -0
  97. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +312 -312
  98. package/src/components/CnVersionInfoCard/index.js +1 -1
  99. package/src/components/CnWidgetRenderer/CnWidgetRenderer.vue +180 -0
  100. package/src/components/CnWidgetRenderer/index.js +1 -0
  101. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +211 -0
  102. package/src/components/CnWidgetWrapper/index.js +1 -0
  103. package/src/components/index.js +43 -29
  104. package/src/composables/index.js +4 -3
  105. package/src/composables/useDashboardView.js +240 -0
  106. package/src/composables/useDetailView.js +289 -132
  107. package/src/composables/useListView.js +363 -153
  108. package/src/composables/useSubResource.js +142 -142
  109. package/src/constants/metadata.js +30 -30
  110. package/src/css/CnSchemaFormDialog.css +546 -0
  111. package/src/css/__sample_nextcloud_tokens.css +110 -0
  112. package/src/css/actions-bar.css +48 -48
  113. package/src/css/badge.css +51 -51
  114. package/src/css/card.css +128 -128
  115. package/src/css/dashboard.css +70 -0
  116. package/src/css/detail-page.css +168 -0
  117. package/src/css/detail.css +68 -68
  118. package/src/css/index-page.css +44 -32
  119. package/src/css/index-sidebar.css +193 -187
  120. package/src/css/index.css +16 -12
  121. package/src/css/layout.css +90 -90
  122. package/src/css/page-header.css +33 -33
  123. package/src/css/pagination.css +72 -72
  124. package/src/css/table.css +142 -142
  125. package/src/css/timeline-stages.css +218 -0
  126. package/src/css/utilities.css +46 -46
  127. package/src/index.js +72 -53
  128. package/src/store/createSubResourcePlugin.js +135 -135
  129. package/src/store/index.js +3 -3
  130. package/src/store/plugins/auditTrails.js +17 -17
  131. package/src/store/plugins/files.js +250 -186
  132. package/src/store/plugins/index.js +7 -5
  133. package/src/store/plugins/lifecycle.js +180 -180
  134. package/src/store/plugins/relations.js +68 -68
  135. package/src/store/plugins/search.js +372 -0
  136. package/src/store/plugins/selection.js +104 -0
  137. package/src/store/useObjectStore.js +829 -686
  138. package/src/types/auditTrail.d.ts +32 -32
  139. package/src/types/file.d.ts +23 -23
  140. package/src/types/index.d.ts +35 -35
  141. package/src/types/notification.d.ts +36 -36
  142. package/src/types/object.d.ts +40 -40
  143. package/src/types/organisation.d.ts +41 -41
  144. package/src/types/register.d.ts +25 -25
  145. package/src/types/schema.d.ts +39 -39
  146. package/src/types/shared.d.ts +79 -79
  147. package/src/types/source.d.ts +14 -14
  148. package/src/types/task.d.ts +31 -31
  149. package/src/utils/errors.js +96 -96
  150. package/src/utils/headers.js +68 -50
  151. package/src/utils/id.js +13 -0
  152. package/src/utils/index.js +3 -3
  153. package/src/utils/schema.js +422 -419
@@ -1 +1 @@
1
- export { default as CnStatsBlock } from './CnStatsBlock.vue'
1
+ export { default as CnStatsBlock } from './CnStatsBlock.vue'
@@ -1,77 +1,77 @@
1
- <template>
2
- <span
3
- class="cn-status-badge"
4
- :class="badgeClasses">
5
- <slot>{{ label }}</slot>
6
- </span>
7
- </template>
8
-
9
- <script>
10
- /**
11
- * CnStatusBadge — Color-coded pill badge for status, priority, or category display.
12
- *
13
- * Replaces the various .status-badge / .priority-badge CSS patterns duplicated
14
- * across Pipelinq and Procest. Supports a colorMap for automatic variant lookup.
15
- *
16
- * @example
17
- * <CnStatusBadge label="Open" variant="success" />
18
- * <CnStatusBadge label="Urgent" variant="error" size="small" />
19
- *
20
- * @example
21
- * <!-- With colorMap: variant auto-resolved from label -->
22
- * <CnStatusBadge
23
- * label="overdue"
24
- * :color-map="{ open: 'success', closed: 'default', overdue: 'error' }" />
25
- */
26
- export default {
27
- name: 'CnStatusBadge',
28
-
29
- props: {
30
- /** Badge label text */
31
- label: {
32
- type: String,
33
- default: '',
34
- },
35
- /**
36
- * Color variant: 'default', 'primary', 'success', 'warning', 'error', 'info'
37
- */
38
- variant: {
39
- type: String,
40
- default: 'default',
41
- validator: (v) => ['default', 'primary', 'success', 'warning', 'error', 'info'].includes(v),
42
- },
43
- /** Size: 'small' or 'medium' */
44
- size: {
45
- type: String,
46
- default: 'medium',
47
- validator: (v) => ['small', 'medium'].includes(v),
48
- },
49
- /**
50
- * Map of label values to variants. When provided, the variant is resolved
51
- * from this map using the label (case-insensitive). Falls back to the variant prop.
52
- * @example { open: 'success', closed: 'default', overdue: 'error' }
53
- */
54
- colorMap: {
55
- type: Object,
56
- default: null,
57
- },
58
- },
59
-
60
- computed: {
61
- resolvedVariant() {
62
- if (this.colorMap && this.label) {
63
- const key = this.label.toLowerCase()
64
- return this.colorMap[key] || this.variant
65
- }
66
- return this.variant
67
- },
68
-
69
- badgeClasses() {
70
- return {
71
- ['cn-status-badge--' + this.resolvedVariant]: true,
72
- 'cn-status-badge--small': this.size === 'small',
73
- }
74
- },
75
- },
76
- }
77
- </script>
1
+ <template>
2
+ <span
3
+ class="cn-status-badge"
4
+ :class="badgeClasses">
5
+ <slot>{{ label }}</slot>
6
+ </span>
7
+ </template>
8
+
9
+ <script>
10
+ /**
11
+ * CnStatusBadge — Color-coded pill badge for status, priority, or category display.
12
+ *
13
+ * Replaces the various .status-badge / .priority-badge CSS patterns duplicated
14
+ * across Pipelinq and Procest. Supports a colorMap for automatic variant lookup.
15
+ *
16
+ * @example
17
+ * <CnStatusBadge label="Open" variant="success" />
18
+ * <CnStatusBadge label="Urgent" variant="error" size="small" />
19
+ *
20
+ * @example
21
+ * <!-- With colorMap: variant auto-resolved from label -->
22
+ * <CnStatusBadge
23
+ * label="overdue"
24
+ * :color-map="{ open: 'success', closed: 'default', overdue: 'error' }" />
25
+ */
26
+ export default {
27
+ name: 'CnStatusBadge',
28
+
29
+ props: {
30
+ /** Badge label text */
31
+ label: {
32
+ type: String,
33
+ default: '',
34
+ },
35
+ /**
36
+ * Color variant: 'default', 'primary', 'success', 'warning', 'error', 'info'
37
+ */
38
+ variant: {
39
+ type: String,
40
+ default: 'default',
41
+ validator: (v) => ['default', 'primary', 'success', 'warning', 'error', 'info'].includes(v),
42
+ },
43
+ /** Size: 'small' or 'medium' */
44
+ size: {
45
+ type: String,
46
+ default: 'medium',
47
+ validator: (v) => ['small', 'medium'].includes(v),
48
+ },
49
+ /**
50
+ * Map of label values to variants. When provided, the variant is resolved
51
+ * from this map using the label (case-insensitive). Falls back to the variant prop.
52
+ * @example { open: 'success', closed: 'default', overdue: 'error' }
53
+ */
54
+ colorMap: {
55
+ type: Object,
56
+ default: null,
57
+ },
58
+ },
59
+
60
+ computed: {
61
+ resolvedVariant() {
62
+ if (this.colorMap && this.label) {
63
+ const key = this.label.toLowerCase()
64
+ return this.colorMap[key] || this.variant
65
+ }
66
+ return this.variant
67
+ },
68
+
69
+ badgeClasses() {
70
+ return {
71
+ ['cn-status-badge--' + this.resolvedVariant]: true,
72
+ 'cn-status-badge--small': this.size === 'small',
73
+ }
74
+ },
75
+ },
76
+ }
77
+ </script>
@@ -1 +1 @@
1
- export { default as CnStatusBadge } from './CnStatusBadge.vue'
1
+ export { default as CnStatusBadge } from './CnStatusBadge.vue'
@@ -0,0 +1,540 @@
1
+ <template>
2
+ <NcDialog
3
+ :name="resolvedTitle"
4
+ :size="size"
5
+ :can-close="!loading"
6
+ @closing="$emit('close')">
7
+ <!-- Result phase (standard mode, not create-another) -->
8
+ <div v-if="result !== null && !createAnother" class="cn-tabbed-form-dialog__result">
9
+ <NcNoteCard v-if="result.success" type="success">
10
+ {{ resolvedSuccessText }}
11
+ </NcNoteCard>
12
+ <NcNoteCard v-if="result.error" type="error">
13
+ {{ result.error }}
14
+ </NcNoteCard>
15
+ </div>
16
+
17
+ <!-- Form phase (or create-another mode where form stays visible) -->
18
+ <div v-if="createAnother || result === null" class="cn-tabbed-form-dialog__form">
19
+ <!-- Inline notifications for create-another mode -->
20
+ <NcNoteCard v-if="createAnother && result && result.success" type="success">
21
+ {{ resolvedSuccessText }}
22
+ </NcNoteCard>
23
+ <NcNoteCard v-if="result && result.error" type="error">
24
+ {{ result.error }}
25
+ </NcNoteCard>
26
+
27
+ <!-- Optional content above tabs (e.g. metadata grid, detail cards) -->
28
+ <slot name="above-tabs" :loading="loading" />
29
+
30
+ <!-- Tabs -->
31
+ <div class="cn-tabbed-form-dialog__tabs tabContainer">
32
+ <BTabs
33
+ v-model="activeTab"
34
+ content-class="mt-3"
35
+ justified
36
+ @input="$emit('update:activeTab', $event)">
37
+ <BTab
38
+ v-for="tab in tabs"
39
+ :key="tab.id"
40
+ :disabled="tab.disabled">
41
+ <template #title>
42
+ <component :is="tab.icon" v-if="tab.icon" :size="16" />
43
+ <span>{{ tab.title }}</span>
44
+ </template>
45
+ <div class="cn-tabbed-form-dialog__tab-content form-editor">
46
+ <slot :name="'tab-' + tab.id" :loading="loading" />
47
+ </div>
48
+ </BTab>
49
+ </BTabs>
50
+ </div>
51
+ </div>
52
+
53
+ <template #actions>
54
+ <!-- Create another checkbox (only in create mode) -->
55
+ <NcCheckboxRadioSwitch
56
+ v-if="showCreateAnother && isCreateMode"
57
+ class="cn-tabbed-form-dialog__create-another"
58
+ :disabled="loading"
59
+ :checked.sync="createAnother">
60
+ {{ createAnotherLabel }}
61
+ </NcCheckboxRadioSwitch>
62
+
63
+ <!-- Extra actions before Cancel -->
64
+ <slot name="actions-left"
65
+ :loading="loading"
66
+ :is-create-mode="isCreateMode"
67
+ :result="result" />
68
+
69
+ <!-- Cancel / Close button -->
70
+ <NcButton @click="handleClose">
71
+ <template #icon>
72
+ <Cancel :size="20" />
73
+ </template>
74
+ {{ result !== null && !createAnother ? closeLabel : cancelLabel }}
75
+ </NcButton>
76
+
77
+ <!-- Extra actions after primary -->
78
+ <slot name="actions-right"
79
+ :loading="loading"
80
+ :is-create-mode="isCreateMode"
81
+ :result="result" />
82
+
83
+ <!-- Primary action button (Save / Create) -->
84
+ <NcButton
85
+ v-if="createAnother || result === null"
86
+ type="primary"
87
+ :disabled="loading || disableSave"
88
+ @click="executeConfirm">
89
+ <template #icon>
90
+ <NcLoadingIcon v-if="loading" :size="20" />
91
+ <Plus v-else-if="isCreateMode" :size="20" />
92
+ <ContentSaveOutline v-else :size="20" />
93
+ </template>
94
+ {{ resolvedConfirmLabel }}
95
+ </NcButton>
96
+ </template>
97
+ </NcDialog>
98
+ </template>
99
+
100
+ <script>
101
+ import {
102
+ NcButton,
103
+ NcDialog,
104
+ NcLoadingIcon,
105
+ NcNoteCard,
106
+ NcCheckboxRadioSwitch,
107
+ } from '@nextcloud/vue'
108
+ import { BTabs, BTab } from 'bootstrap-vue'
109
+
110
+ import Cancel from 'vue-material-design-icons/Cancel.vue'
111
+ import ContentSaveOutline from 'vue-material-design-icons/ContentSaveOutline.vue'
112
+ import Plus from 'vue-material-design-icons/Plus.vue'
113
+
114
+ export default {
115
+ name: 'CnTabbedFormDialog',
116
+ components: {
117
+ NcDialog,
118
+ NcButton,
119
+ NcLoadingIcon,
120
+ NcNoteCard,
121
+ NcCheckboxRadioSwitch,
122
+ BTabs,
123
+ BTab,
124
+ Cancel,
125
+ ContentSaveOutline,
126
+ Plus,
127
+ },
128
+ props: {
129
+ /**
130
+ * Array of tab definitions. Each tab must have at least an `id` and `title`.
131
+ * The optional `icon` field should be a Vue component reference (e.g. an imported MDI icon).
132
+ * The optional `disabled` field prevents tab selection.
133
+ *
134
+ * @type {Array<{ id: string, title: string, icon?: object, disabled?: boolean }>}
135
+ */
136
+ tabs: {
137
+ type: Array,
138
+ required: true,
139
+ validator: (tabs) => tabs.length > 0 && tabs.every(t => t.id && t.title),
140
+ },
141
+ /**
142
+ * Existing item for edit mode. Pass null or undefined for create mode.
143
+ * The component only checks for truthiness to determine create vs edit mode.
144
+ *
145
+ * @type {object|null}
146
+ */
147
+ item: {
148
+ type: Object,
149
+ default: null,
150
+ },
151
+ /**
152
+ * Custom dialog title. When provided, overrides the auto-generated
153
+ * "Create {entityName}" / "Edit {entityName}" title.
154
+ *
155
+ * @type {string}
156
+ */
157
+ dialogTitle: {
158
+ type: String,
159
+ default: '',
160
+ },
161
+ /**
162
+ * Entity name used in auto-generated titles and success messages.
163
+ * For example, "Organisation" produces "Create Organisation" and
164
+ * "Organisation saved successfully".
165
+ *
166
+ * @type {string}
167
+ */
168
+ entityName: {
169
+ type: String,
170
+ default: 'Item',
171
+ },
172
+ /**
173
+ * NcDialog size. One of 'small', 'normal', 'large', 'full'.
174
+ *
175
+ * @type {string}
176
+ */
177
+ size: {
178
+ type: String,
179
+ default: 'large',
180
+ },
181
+ /**
182
+ * Whether to show the "Create Another" checkbox in create mode.
183
+ * When checked and a save succeeds, the form stays open and a reset
184
+ * event is emitted so the parent can clear form data.
185
+ *
186
+ * @type {boolean}
187
+ */
188
+ showCreateAnother: {
189
+ type: Boolean,
190
+ default: false,
191
+ },
192
+ /**
193
+ * Whether the primary save/create button is disabled.
194
+ * The parent controls validation externally.
195
+ *
196
+ * @type {boolean}
197
+ */
198
+ disableSave: {
199
+ type: Boolean,
200
+ default: false,
201
+ },
202
+ /**
203
+ * Custom success message shown in the result NcNoteCard.
204
+ * Defaults to "{entityName} saved successfully".
205
+ *
206
+ * @type {string}
207
+ */
208
+ successText: {
209
+ type: String,
210
+ default: '',
211
+ },
212
+ /**
213
+ * Cancel button label.
214
+ *
215
+ * @type {string}
216
+ */
217
+ cancelLabel: {
218
+ type: String,
219
+ default: 'Cancel',
220
+ },
221
+ /**
222
+ * Close button label shown in the result phase.
223
+ *
224
+ * @type {string}
225
+ */
226
+ closeLabel: {
227
+ type: String,
228
+ default: 'Close',
229
+ },
230
+ /**
231
+ * Primary confirm button label. Defaults to "Create" in create mode
232
+ * or "Save" in edit mode.
233
+ *
234
+ * @type {string}
235
+ */
236
+ confirmLabel: {
237
+ type: String,
238
+ default: '',
239
+ },
240
+ /**
241
+ * Label for the "Create Another" checkbox.
242
+ *
243
+ * @type {string}
244
+ */
245
+ createAnotherLabel: {
246
+ type: String,
247
+ default: 'Create another',
248
+ },
249
+ },
250
+ data() {
251
+ return {
252
+ /** @type {number} Current active tab index */
253
+ activeTab: 0,
254
+ /** @type {boolean} Whether the "create another" checkbox is checked */
255
+ createAnother: false,
256
+ /** @type {boolean} Whether an API operation is in progress */
257
+ loading: false,
258
+ /**
259
+ * Result of the last operation.
260
+ * null = form phase, { success: true } = success, { error: 'msg' } = error
261
+ *
262
+ * @type {{ success?: boolean, error?: string }|null}
263
+ */
264
+ result: null,
265
+ /** @type {number|null} Timeout ID for auto-close after success */
266
+ closeTimeout: null,
267
+ /** @type {number|null} Timeout ID for clearing success in create-another mode */
268
+ successClearTimeout: null,
269
+ }
270
+ },
271
+ computed: {
272
+ /**
273
+ * Whether the dialog is in create mode (no existing item).
274
+ *
275
+ * @return {boolean}
276
+ */
277
+ isCreateMode() {
278
+ return !this.item
279
+ },
280
+ /**
281
+ * Resolved dialog title. Uses dialogTitle prop if provided,
282
+ * otherwise auto-generates from entityName and mode.
283
+ *
284
+ * @return {string}
285
+ */
286
+ resolvedTitle() {
287
+ if (this.dialogTitle) {
288
+ return this.dialogTitle
289
+ }
290
+ return this.isCreateMode
291
+ ? `Create ${this.entityName}`
292
+ : `Edit ${this.entityName}`
293
+ },
294
+ /**
295
+ * Resolved success text for NcNoteCard.
296
+ *
297
+ * @return {string}
298
+ */
299
+ resolvedSuccessText() {
300
+ if (this.successText) {
301
+ return this.successText
302
+ }
303
+ return `${this.entityName} saved successfully`
304
+ },
305
+ /**
306
+ * Resolved primary button label.
307
+ *
308
+ * @return {string}
309
+ */
310
+ resolvedConfirmLabel() {
311
+ if (this.confirmLabel) {
312
+ return this.confirmLabel
313
+ }
314
+ return this.isCreateMode ? 'Create' : 'Save'
315
+ },
316
+ },
317
+ beforeDestroy() {
318
+ clearTimeout(this.closeTimeout)
319
+ clearTimeout(this.successClearTimeout)
320
+ },
321
+ methods: {
322
+ /**
323
+ * Set the result of the save operation. Call this from the parent
324
+ * after the API call completes.
325
+ *
326
+ * When success is true and create-another is not checked, the dialog
327
+ * auto-closes after 2 seconds. When create-another is checked,
328
+ * the success message shows inline for 2 seconds, then clears and
329
+ * emits the `reset` event.
330
+ *
331
+ * @param {{ success?: boolean, error?: string }} resultData
332
+ * @public
333
+ */
334
+ setResult(resultData) {
335
+ this.loading = false
336
+ this.result = resultData
337
+
338
+ if (resultData.success) {
339
+ if (this.createAnother) {
340
+ // Create-another mode: show success briefly, then reset
341
+ this.successClearTimeout = setTimeout(() => {
342
+ this.result = null
343
+ this.activeTab = 0
344
+ /**
345
+ * Emitted after a successful save in create-another mode.
346
+ * The parent should clear its form data.
347
+ *
348
+ * @event reset
349
+ */
350
+ this.$emit('reset')
351
+ }, 2000)
352
+ } else {
353
+ // Standard mode: auto-close after 2 seconds
354
+ this.closeTimeout = setTimeout(() => {
355
+ /**
356
+ * Emitted when the dialog should be closed.
357
+ *
358
+ * @event close
359
+ */
360
+ this.$emit('close')
361
+ }, 2000)
362
+ }
363
+ }
364
+ },
365
+
366
+ /**
367
+ * Reset the dialog to its initial form state.
368
+ * Clears any result, resets loading, and returns to the first tab.
369
+ *
370
+ * @public
371
+ */
372
+ resetDialog() {
373
+ clearTimeout(this.closeTimeout)
374
+ clearTimeout(this.successClearTimeout)
375
+ this.result = null
376
+ this.loading = false
377
+ this.activeTab = 0
378
+ },
379
+
380
+ /**
381
+ * Handle the primary action button click.
382
+ * Sets loading state and emits the confirm event.
383
+ *
384
+ * @private
385
+ */
386
+ executeConfirm() {
387
+ this.loading = true
388
+ this.result = null
389
+ /**
390
+ * Emitted when the user clicks Save/Create.
391
+ * The parent should perform the API call and then call setResult().
392
+ *
393
+ * @event confirm
394
+ */
395
+ this.$emit('confirm')
396
+ },
397
+
398
+ /**
399
+ * Handle close button click. Clears timeouts and emits close.
400
+ *
401
+ * @private
402
+ */
403
+ handleClose() {
404
+ clearTimeout(this.closeTimeout)
405
+ clearTimeout(this.successClearTimeout)
406
+ this.result = null
407
+ this.loading = false
408
+ this.createAnother = false
409
+ this.activeTab = 0
410
+ this.$emit('close')
411
+ },
412
+ },
413
+ }
414
+ </script>
415
+
416
+ <style scoped>
417
+ /* Result phase container */
418
+ .cn-tabbed-form-dialog__result {
419
+ padding: 16px 0;
420
+ }
421
+
422
+ /* Form phase container */
423
+ .cn-tabbed-form-dialog__form {
424
+ display: flex;
425
+ flex-direction: column;
426
+ gap: 8px;
427
+ }
428
+
429
+ /* Tabs wrapper */
430
+ .cn-tabbed-form-dialog__tabs {
431
+ display: flex;
432
+ flex-direction: column;
433
+ gap: 12px;
434
+ }
435
+
436
+ /* Tab content area — also uses .form-editor for compatibility */
437
+ .cn-tabbed-form-dialog__tab-content {
438
+ display: flex;
439
+ flex-direction: column;
440
+ gap: 16px;
441
+ padding: 16px 0;
442
+ }
443
+
444
+ /* Create another checkbox — push to the left in actions area */
445
+ .cn-tabbed-form-dialog__create-another {
446
+ margin-right: auto;
447
+ }
448
+
449
+ /* Bootstrap-Vue tab container styling */
450
+ .tabContainer > * ul > li {
451
+ display: flex;
452
+ flex: 1;
453
+ }
454
+
455
+ .tabContainer > * ul > li:hover {
456
+ background-color: var(--color-background-hover);
457
+ }
458
+
459
+ .tabContainer > * ul > li > a {
460
+ flex: 1;
461
+ text-align: center;
462
+ }
463
+
464
+ .tabContainer > * ul > li > .active {
465
+ background: transparent !important;
466
+ color: var(--color-main-text) !important;
467
+ border-bottom: var(--default-grid-baseline) solid var(--color-primary-element) !important;
468
+ }
469
+
470
+ .tabContainer > * ul[role="tablist"] {
471
+ display: flex;
472
+ margin: 10px 8px 0 8px;
473
+ justify-content: space-between;
474
+ border-bottom: 1px solid var(--color-border);
475
+ }
476
+
477
+ .tabContainer > * ul[role="tablist"] > * a[role="tab"] {
478
+ padding-inline-start: 10px;
479
+ padding-inline-end: 10px;
480
+ padding-block-start: 10px;
481
+ padding-block-end: 10px;
482
+ }
483
+
484
+ .tabContainer > * div[role="tabpanel"] {
485
+ margin-block-start: var(--OR-margin-10);
486
+ }
487
+
488
+ :deep(.nav-tabs) {
489
+ border-bottom: 1px solid var(--color-border);
490
+ margin-bottom: 15px;
491
+ display: flex;
492
+ }
493
+
494
+ :deep(.nav-tabs .nav-item) {
495
+ display: flex;
496
+ flex: 1;
497
+ }
498
+
499
+ :deep(.nav-tabs .nav-link) {
500
+ flex: 1;
501
+ text-align: center;
502
+ border: none;
503
+ border-bottom: 2px solid transparent;
504
+ color: var(--color-text-maxcontrast);
505
+ padding: 8px 16px;
506
+ display: flex;
507
+ align-items: center;
508
+ gap: 8px;
509
+ justify-content: center;
510
+ }
511
+
512
+ :deep(.nav-tabs .nav-link.active) {
513
+ color: var(--color-main-text);
514
+ border-bottom: 2px solid var(--color-primary);
515
+ background-color: transparent;
516
+ }
517
+
518
+ :deep(.nav-tabs .nav-link:hover) {
519
+ border-bottom: 2px solid var(--color-border);
520
+ }
521
+
522
+ :deep(.nav-tabs .nav-link.disabled) {
523
+ cursor: not-allowed;
524
+ opacity: 0.5;
525
+ color: var(--color-text-maxcontrast);
526
+ pointer-events: auto;
527
+ }
528
+ :deep(.nav-tabs .nav-link.disabled *) {
529
+ cursor: not-allowed;
530
+ }
531
+
532
+ :deep(.nav-tabs .nav-link.disabled:hover) {
533
+ border-bottom: 2px solid transparent;
534
+ }
535
+
536
+ :deep(.tab-content) {
537
+ padding: 16px;
538
+ background-color: var(--color-main-background);
539
+ }
540
+ </style>
@@ -0,0 +1 @@
1
+ export { default as CnTabbedFormDialog } from './CnTabbedFormDialog.vue'