@conduction/nextcloud-vue 2.99.0 → 2.101.0
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/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +6 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +2 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js +22 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +26 -16
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +51 -7
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +104 -73
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +25 -8
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +5 -3
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +11 -8
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +13 -4
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js +9 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js +139 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js +76 -0
- package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +54 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +16 -2
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +160 -2
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +206 -94
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesReview.js +61 -0
- package/dist/esm/components/CnFilesBrowser/filesReview.js.map +1 -0
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +42 -7
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +121 -57
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue2.js +10 -0
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue3.js +2 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue3.js.map +1 -1
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js +9 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js +279 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js +122 -0
- package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnGroupedCardsWidget/index.js +29 -0
- package/dist/esm/components/CnGroupedCardsWidget/index.js.map +1 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +387 -78
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +317 -209
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js +4 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +15 -0
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +14 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +14 -6
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +10 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +6 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +91 -4
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +63 -38
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +68 -7
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +256 -240
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js +9 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js +175 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js +77 -0
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue.js +1 -1
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue2.js +38 -9
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +51 -4
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +40 -25
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +4 -0
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue.js +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js +7 -7
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +167 -20
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/composables/useEndpointSource.js +28 -6
- package/dist/esm/composables/useEndpointSource.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +43 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +41 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +1101 -396
- package/dist/esm/utils/languageMapText.js +50 -0
- package/dist/esm/utils/languageMapText.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +3 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/mapList.js +71 -0
- package/dist/esm/utils/mapList.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +9996 -7378
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1101 -396
- package/l10n/en.json +43 -1
- package/l10n/nl.json +41 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +7 -1
- package/src/components/CnChoiceCards/CnChoiceCards.md +39 -0
- package/src/components/CnChoiceCards/CnChoiceCards.vue +93 -16
- package/src/components/CnDashboardPage/CnDashboardPage.vue +89 -20
- package/src/components/CnDetailPage/CnDetailPage.vue +28 -9
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +13 -4
- package/src/components/CnExportsWidget/CnExportsWidget.vue +233 -0
- package/src/components/CnExportsWidget/index.js +7 -0
- package/src/components/CnFactsWidget/CnFactsWidget.vue +65 -3
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +324 -0
- package/src/components/CnFilesBrowser/filesReview.js +57 -0
- package/src/components/CnFlowsPage/CnFlowBoard.vue +77 -2
- package/src/components/CnFlowsPage/CnFlowEditorPage.vue +11 -0
- package/src/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue +433 -0
- package/src/components/CnGroupedCardsWidget/index.js +28 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +376 -11
- package/src/components/CnIndexPage/useNamedSource.js +4 -1
- package/src/components/CnMapWidget/CnMapWidget.vue +37 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +29 -1
- package/src/components/CnObjectSidebar/CnFilesTab.vue +15 -0
- package/src/components/CnOrderedListField/CnOrderedListField.vue +151 -5
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +114 -7
- package/src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue +272 -0
- package/src/components/CnSavedViewAlertWidget/index.js +7 -0
- package/src/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue +38 -9
- package/src/components/CnSetupWizard/CnSetupWizard.vue +72 -5
- package/src/components/CnWidgetGrid/builtInWidgets.js +4 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/src/components/CnWizardDialog/CnWizardDialog.vue +7 -7
- package/src/components/index.js +3 -0
- package/src/composables/indexSources.js +166 -19
- package/src/composables/useEndpointSource.js +28 -6
- package/src/css/detail-page.css +15 -0
- package/src/css/dialog.css +48 -0
- package/src/css/index-page.css +117 -0
- package/src/css/look-board.css +127 -1
- package/src/index.js +1 -0
- package/src/schemas/app-manifest-v2.schema.json +55 -1
- package/src/utils/languageMapText.js +46 -0
- package/src/utils/libraryWidgetKeys.js +3 -0
- package/src/utils/mapList.js +67 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
- SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
- SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
-->
|
|
5
|
+
<template>
|
|
6
|
+
<div class="cn-saved-view-alert" data-testid="cn-saved-view-alert">
|
|
7
|
+
<p v-if="!view" class="cn-saved-view-alert__empty" data-testid="cn-saved-view-alert-empty">
|
|
8
|
+
{{ emptyText }}
|
|
9
|
+
</p>
|
|
10
|
+
<template v-else>
|
|
11
|
+
<dl class="cn-saved-view-alert__facts">
|
|
12
|
+
<dt>{{ t('nextcloud-vue', 'Name') }}</dt>
|
|
13
|
+
<dd data-testid="cn-saved-view-alert-name">
|
|
14
|
+
{{ view.name }}
|
|
15
|
+
</dd>
|
|
16
|
+
<template v-if="countText">
|
|
17
|
+
<dt>{{ t('nextcloud-vue', 'Now') }}</dt>
|
|
18
|
+
<dd data-testid="cn-saved-view-alert-count">
|
|
19
|
+
{{ countText }}
|
|
20
|
+
</dd>
|
|
21
|
+
</template>
|
|
22
|
+
</dl>
|
|
23
|
+
<NcCheckboxRadioSwitch
|
|
24
|
+
type="switch"
|
|
25
|
+
:modelValue="enabled"
|
|
26
|
+
:disabled="saving || !canEdit"
|
|
27
|
+
data-testid="cn-saved-view-alert-switch"
|
|
28
|
+
@update:modelValue="onToggle">
|
|
29
|
+
<span class="cn-saved-view-alert__switch-text">
|
|
30
|
+
<span>{{ t('nextcloud-vue', 'Tell me above a number') }}</span>
|
|
31
|
+
<span class="cn-saved-view-alert__hint">{{ hintText }}</span>
|
|
32
|
+
</span>
|
|
33
|
+
</NcCheckboxRadioSwitch>
|
|
34
|
+
<NcTextField v-if="enabled"
|
|
35
|
+
:modelValue="String(threshold)"
|
|
36
|
+
type="number"
|
|
37
|
+
min="0"
|
|
38
|
+
:label="t('nextcloud-vue', 'Threshold')"
|
|
39
|
+
:disabled="saving || !canEdit"
|
|
40
|
+
data-testid="cn-saved-view-alert-threshold"
|
|
41
|
+
@update:modelValue="onThreshold" />
|
|
42
|
+
<p v-if="error"
|
|
43
|
+
class="cn-saved-view-alert__error"
|
|
44
|
+
role="alert"
|
|
45
|
+
data-testid="cn-saved-view-alert-error">
|
|
46
|
+
{{ error }}
|
|
47
|
+
</p>
|
|
48
|
+
</template>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script>
|
|
53
|
+
import { getCurrentUser } from '@nextcloud/auth'
|
|
54
|
+
import { translatePlural as n, translate as t } from '@nextcloud/l10n'
|
|
55
|
+
import { NcCheckboxRadioSwitch, NcTextField } from '@nextcloud/vue'
|
|
56
|
+
import { useSavedViewsApi } from '../../composables/useSavedViewsApi.js'
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* CnSavedViewAlertWidget — the saved view an index page has applied, with its
|
|
60
|
+
* count alert (DqZoekresultaten "Opgeslagen zoekopdracht"): its name, how many
|
|
61
|
+
* rows it holds now, and a switch that asks OpenRegister to tell the reader
|
|
62
|
+
* when the count reaches a threshold.
|
|
63
|
+
*
|
|
64
|
+
* The alert is the view's own `alert` (`{ operator: 'gte', threshold,
|
|
65
|
+
* recipients }`), saved with a PATCH on the view; OpenRegister evaluates it on
|
|
66
|
+
* its sweep and fires on the crossing, not on the state. Switching it off
|
|
67
|
+
* clears it. The widget reads the page through the `cnIndexList` CnIndexPage
|
|
68
|
+
* provides, so it belongs in an index page's `sidePanel`
|
|
69
|
+
* (`type: "saved-view-alert"`).
|
|
70
|
+
*
|
|
71
|
+
* Example (manifest):
|
|
72
|
+
* ```json
|
|
73
|
+
* { "id": "alert", "type": "saved-view-alert", "title": "Saved search", "content": { "noun": { "one": "case", "other": "cases" } } }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export default {
|
|
77
|
+
name: 'CnSavedViewAlertWidget',
|
|
78
|
+
|
|
79
|
+
components: { NcCheckboxRadioSwitch, NcTextField },
|
|
80
|
+
|
|
81
|
+
inject: {
|
|
82
|
+
/** The index page's list: its applied saved view and its total. */
|
|
83
|
+
cnIndexList: { default: null },
|
|
84
|
+
/** Host translate function provided by CnAppRoot. */
|
|
85
|
+
cnTranslate: { default: () => (key) => key },
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
props: {
|
|
89
|
+
/**
|
|
90
|
+
* The widget content: `{ noun?: { one, other }, emptyText? }`. `noun`
|
|
91
|
+
* names what is counted ("9 zaken"); `emptyText` shows while no saved
|
|
92
|
+
* view is applied. Both are translated with the app's catalogue.
|
|
93
|
+
*/
|
|
94
|
+
content: {
|
|
95
|
+
type: Object,
|
|
96
|
+
default: () => ({}),
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
data() {
|
|
101
|
+
return { saving: false, error: '', draft: null }
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
computed: {
|
|
105
|
+
/** @return {object|null} The applied saved view, or null. */
|
|
106
|
+
view() {
|
|
107
|
+
return (this.cnIndexList && this.cnIndexList.appliedView) || null
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/** @return {boolean} Whether the view carries an alert. */
|
|
111
|
+
enabled() {
|
|
112
|
+
const alert = this.view && this.view.alert
|
|
113
|
+
return Boolean(alert && typeof alert === 'object' && Number.isFinite(Number(alert.threshold)))
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/** @return {number} The threshold being edited, else the view's, else 10. */
|
|
117
|
+
threshold() {
|
|
118
|
+
if (this.draft !== null) {
|
|
119
|
+
return this.draft
|
|
120
|
+
}
|
|
121
|
+
const value = this.enabled ? Number(this.view.alert.threshold) : 10
|
|
122
|
+
return Number.isFinite(value) ? value : 10
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/** @return {boolean} Whether the reader may change the view: its owner, or when the view says nothing. */
|
|
126
|
+
canEdit() {
|
|
127
|
+
const owner = this.view && this.view.owner
|
|
128
|
+
if (!owner) {
|
|
129
|
+
return true
|
|
130
|
+
}
|
|
131
|
+
const user = getCurrentUser()
|
|
132
|
+
return Boolean(user && user.uid === owner)
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
/** @return {string} "9 zaken", or '' while the total is unknown. */
|
|
136
|
+
countText() {
|
|
137
|
+
const total = this.cnIndexList ? this.cnIndexList.total : undefined
|
|
138
|
+
if (typeof total !== 'number') {
|
|
139
|
+
return ''
|
|
140
|
+
}
|
|
141
|
+
const noun = this.content && this.content.noun
|
|
142
|
+
if (noun && typeof noun === 'object' && noun.one && noun.other) {
|
|
143
|
+
return `${total} ${this.cnTranslate(total === 1 ? noun.one : noun.other)}`
|
|
144
|
+
}
|
|
145
|
+
return n('nextcloud-vue', '%n result', '%n results', total)
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
/** @return {string} The line under the switch. */
|
|
149
|
+
hintText() {
|
|
150
|
+
return t('nextcloud-vue', 'A message to you when there are {threshold} or more', { threshold: this.threshold })
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
/** @return {string} What shows while no saved view is applied. */
|
|
154
|
+
emptyText() {
|
|
155
|
+
const own = this.content && this.content.emptyText
|
|
156
|
+
return own ? this.cnTranslate(own) : t('nextcloud-vue', 'Save this search or open a saved one to set an alert on it.')
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
methods: {
|
|
161
|
+
t,
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Switch the alert on (at the shown threshold) or off.
|
|
165
|
+
*
|
|
166
|
+
* @param {boolean} on The new state.
|
|
167
|
+
* @return {Promise<void>}
|
|
168
|
+
*/
|
|
169
|
+
async onToggle(on) {
|
|
170
|
+
await this.save(on ? this.alertFor(this.threshold) : null)
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Save a new threshold, when the alert is on.
|
|
175
|
+
*
|
|
176
|
+
* @param {string} value The typed value.
|
|
177
|
+
* @return {Promise<void>}
|
|
178
|
+
*/
|
|
179
|
+
async onThreshold(value) {
|
|
180
|
+
const number = Math.max(0, Math.floor(Number(value)))
|
|
181
|
+
if (!Number.isFinite(number)) {
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
this.draft = number
|
|
185
|
+
await this.save(this.alertFor(number))
|
|
186
|
+
this.draft = null
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The alert the view stores: reaching the threshold tells the reader.
|
|
191
|
+
*
|
|
192
|
+
* @param {number} threshold The threshold.
|
|
193
|
+
* @return {{operator: string, threshold: number, recipients: Array<string>}}
|
|
194
|
+
*/
|
|
195
|
+
alertFor(threshold) {
|
|
196
|
+
const user = getCurrentUser()
|
|
197
|
+
return { operator: 'gte', threshold, recipients: user && user.uid ? [user.uid] : [] }
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* PATCH the view's alert and hand the saved view back to the page.
|
|
202
|
+
*
|
|
203
|
+
* @param {object|null} alert The alert, or null to clear it.
|
|
204
|
+
* @return {Promise<void>}
|
|
205
|
+
*/
|
|
206
|
+
async save(alert) {
|
|
207
|
+
if (!this.view) {
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
this.saving = true
|
|
211
|
+
this.error = ''
|
|
212
|
+
try {
|
|
213
|
+
const saved = await useSavedViewsApi().patchView(this.view.uuid || this.view.id, { alert })
|
|
214
|
+
if (saved && this.cnIndexList && typeof this.cnIndexList.replaceSavedView === 'function') {
|
|
215
|
+
this.cnIndexList.replaceSavedView(saved)
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
this.error = (error && error.response && error.response.data && error.response.data.error) || t('nextcloud-vue', 'The alert could not be saved.')
|
|
219
|
+
} finally {
|
|
220
|
+
this.saving = false
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
}
|
|
225
|
+
</script>
|
|
226
|
+
|
|
227
|
+
<style scoped>
|
|
228
|
+
.cn-saved-view-alert {
|
|
229
|
+
display: flex;
|
|
230
|
+
flex-direction: column;
|
|
231
|
+
gap: 12px;
|
|
232
|
+
font-size: 14px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.cn-saved-view-alert__facts {
|
|
236
|
+
display: grid;
|
|
237
|
+
grid-template-columns: max-content 1fr;
|
|
238
|
+
gap: 6px 16px;
|
|
239
|
+
margin: 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.cn-saved-view-alert__facts dt {
|
|
243
|
+
color: var(--color-text-maxcontrast);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.cn-saved-view-alert__facts dd {
|
|
247
|
+
margin: 0;
|
|
248
|
+
font-weight: 500;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.cn-saved-view-alert__switch-text {
|
|
252
|
+
display: flex;
|
|
253
|
+
flex-direction: column;
|
|
254
|
+
gap: 2px;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.cn-saved-view-alert__hint,
|
|
258
|
+
.cn-saved-view-alert__empty {
|
|
259
|
+
color: var(--color-text-maxcontrast);
|
|
260
|
+
font-size: 13px;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.cn-saved-view-alert__empty,
|
|
264
|
+
.cn-saved-view-alert__error {
|
|
265
|
+
margin: 0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.cn-saved-view-alert__error {
|
|
269
|
+
color: var(--color-error-text, var(--color-error));
|
|
270
|
+
font-size: 13px;
|
|
271
|
+
}
|
|
272
|
+
</style>
|
|
@@ -68,6 +68,32 @@ import { serverErrorMessage } from '../../utils/serverErrorMessage.js'
|
|
|
68
68
|
import { CnSettingsField } from '../CnSettingsField/index.js'
|
|
69
69
|
import { CnSettingsSection } from '../CnSettingsSection/index.js'
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* A value by key: the key as written when the object holds it (a flat map
|
|
73
|
+
* with dotted keys such as `integration.brk.mode`), else as a dotted path.
|
|
74
|
+
*
|
|
75
|
+
* @param {object} data The object.
|
|
76
|
+
* @param {string} key The key or dotted path.
|
|
77
|
+
* @return {unknown}
|
|
78
|
+
*/
|
|
79
|
+
function literalFirst(data, key) {
|
|
80
|
+
if (data && typeof data === 'object' && Object.hasOwn(data, key)) {
|
|
81
|
+
return data[key]
|
|
82
|
+
}
|
|
83
|
+
return readPath(data, key)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The request options for a target: an OCS endpoint (`/ocs/...`) needs the
|
|
88
|
+
* `OCS-APIRequest` header; `prefixUrl` already serves it outside index.php.
|
|
89
|
+
*
|
|
90
|
+
* @param {string} url The target.
|
|
91
|
+
* @return {object}
|
|
92
|
+
*/
|
|
93
|
+
function ocsConfig(url) {
|
|
94
|
+
return /^\/ocs\//.test(String(url)) ? { headers: { 'OCS-APIRequest': 'true' } } : {}
|
|
95
|
+
}
|
|
96
|
+
|
|
71
97
|
/**
|
|
72
98
|
* Up to two initials of a name, for an image field without an image.
|
|
73
99
|
*
|
|
@@ -146,15 +172,16 @@ export default {
|
|
|
146
172
|
* The fields: `[{ key, label, type?, hint?, placeholder?, required?,
|
|
147
173
|
* pattern?, patternMessage?, min?, max?, rows?, options?, optionsUrl?,
|
|
148
174
|
* optionsPath?, optionLabel?, optionValue?, default?, readOnly?, wide?,
|
|
149
|
-
* url?, valuePath?, saveUrl?, saveMethod?, saveKey?, uploadUrl?,
|
|
175
|
+
* url?, valuePath?, saveUrl?, saveMethod?, saveKey?, saveParams?, uploadUrl?,
|
|
150
176
|
* uploadField?, uploadParams?, uploadValuePath?, initials?, initialsFrom? }]`.
|
|
151
177
|
* `type` is `text` (default), `textarea`, `number`, `switch`, `select`,
|
|
152
178
|
* `secret` or `image`. `key` names the setting; a dotted key reads a
|
|
153
179
|
* nested value and is written as written. A field with its own `url`
|
|
154
180
|
* is read there (at `valuePath`, default its key) and saved to its
|
|
155
181
|
* `saveUrl` (default that `url`) with `saveMethod` (default POST) under
|
|
156
|
-
* `saveKey` (default its key),
|
|
157
|
-
*
|
|
182
|
+
* `saveKey` (default its key), with `saveParams` merged into the body,
|
|
183
|
+
* so one section can hold the settings of several apps. A target under
|
|
184
|
+
* `/ocs/` is sent the `OCS-APIRequest` header. An `image` uploads at once to `uploadUrl`. Labels,
|
|
158
185
|
* hints, placeholders and messages go through the app's translate
|
|
159
186
|
* function.
|
|
160
187
|
*
|
|
@@ -343,7 +370,7 @@ export default {
|
|
|
343
370
|
const failures = {}
|
|
344
371
|
await Promise.all(targets.map(async (target) => {
|
|
345
372
|
try {
|
|
346
|
-
const response = await axios.get(prefixUrl(target))
|
|
373
|
+
const response = await axios.get(prefixUrl(target), ocsConfig(target))
|
|
347
374
|
answers[target] = response?.data ?? {}
|
|
348
375
|
} catch (error) {
|
|
349
376
|
failures[target] = error
|
|
@@ -396,7 +423,8 @@ export default {
|
|
|
396
423
|
|
|
397
424
|
/**
|
|
398
425
|
* A field's value in its read answer: at its `valuePath` (a field with its
|
|
399
|
-
* own `url`), else at the section's `valuesPath`, then its `key`.
|
|
426
|
+
* own `url`), else at the section's `valuesPath`, then its `key`. A key
|
|
427
|
+
* the answer holds as written wins over reading it as a dotted path.
|
|
400
428
|
*
|
|
401
429
|
* @param {object} field The field.
|
|
402
430
|
* @param {object|null} data The answer of the field's read target.
|
|
@@ -407,10 +435,10 @@ export default {
|
|
|
407
435
|
return undefined
|
|
408
436
|
}
|
|
409
437
|
if (field.url) {
|
|
410
|
-
return
|
|
438
|
+
return literalFirst(data, field.valuePath || field.key)
|
|
411
439
|
}
|
|
412
|
-
const values = (this.valuesPath ?
|
|
413
|
-
return
|
|
440
|
+
const values = (this.valuesPath ? literalFirst(data, this.valuesPath) : data) || {}
|
|
441
|
+
return literalFirst(values, field.key)
|
|
414
442
|
},
|
|
415
443
|
|
|
416
444
|
/**
|
|
@@ -494,6 +522,7 @@ export default {
|
|
|
494
522
|
}
|
|
495
523
|
const group = groups.get(id)
|
|
496
524
|
group.fields.push(field)
|
|
525
|
+
Object.assign(group.data, field.saveParams || {})
|
|
497
526
|
group.data[field.saveKey || field.key] = value
|
|
498
527
|
}
|
|
499
528
|
this.saving = true
|
|
@@ -502,7 +531,7 @@ export default {
|
|
|
502
531
|
const sent = {}
|
|
503
532
|
for (const group of groups.values()) {
|
|
504
533
|
try {
|
|
505
|
-
await axios.request({ url: prefixUrl(group.url), method: group.method, data: group.data })
|
|
534
|
+
await axios.request({ url: prefixUrl(group.url), method: group.method, data: group.data, ...ocsConfig(group.url) })
|
|
506
535
|
Object.assign(sent, group.data)
|
|
507
536
|
this.acceptSaved(group.fields)
|
|
508
537
|
} catch (error) {
|
|
@@ -69,7 +69,12 @@
|
|
|
69
69
|
|
|
70
70
|
<!-- choice -->
|
|
71
71
|
<template v-else-if="step.type === 'choice'">
|
|
72
|
-
|
|
72
|
+
<!-- The board sets the intro as a plain paragraph above the
|
|
73
|
+
cards (DqInstellen); the Nextcloud look keeps the note. -->
|
|
74
|
+
<p v-if="step.body && isBoard" class="cn-setup-step__intro" data-testid="cn-setup-step-intro">
|
|
75
|
+
{{ stepBody(step) }}
|
|
76
|
+
</p>
|
|
77
|
+
<NcNoteCard v-else-if="step.body" type="info">
|
|
73
78
|
{{ stepBody(step) }}
|
|
74
79
|
</NcNoteCard>
|
|
75
80
|
<CnChoiceCards
|
|
@@ -119,6 +124,9 @@
|
|
|
119
124
|
<NcNoteCard v-if="isChoiceDisabled(step)" type="warning">
|
|
120
125
|
{{ dependsOnHint(step) }}
|
|
121
126
|
</NcNoteCard>
|
|
127
|
+
<p v-if="stepNote(step)" class="cn-setup-step__note" data-testid="cn-setup-step-note">
|
|
128
|
+
{{ stepNote(step) }}
|
|
129
|
+
</p>
|
|
122
130
|
</template>
|
|
123
131
|
|
|
124
132
|
<!-- config-fields -->
|
|
@@ -212,6 +220,7 @@ import CnChoiceCards from '../CnChoiceCards/CnChoiceCards.vue'
|
|
|
212
220
|
import CnLeafDependencySettings from '../CnLeafDependencySettings/CnLeafDependencySettings.vue'
|
|
213
221
|
import CnWizardDialog from '../CnWizardDialog/CnWizardDialog.vue'
|
|
214
222
|
import { checkDependencies, isDependencyResolved, missingRequiredApps, readServerAppStatuses } from '../../composables/useDependencyCheck.js'
|
|
223
|
+
import { useLook } from '../../composables/useLook.js'
|
|
215
224
|
import { useSetupStatus } from '../../composables/useSetupStatus.js'
|
|
216
225
|
import { fieldsFromSchema } from '../../utils/schema.js'
|
|
217
226
|
|
|
@@ -428,12 +437,13 @@ export default {
|
|
|
428
437
|
* @return {object} `setupStatus` / `setupStatusLoading` for the option resolver.
|
|
429
438
|
*/
|
|
430
439
|
setup(props) {
|
|
431
|
-
const
|
|
440
|
+
const { isBoard } = useLook()
|
|
441
|
+
const wantsSource = (props.steps || []).some((s) => s && (s.optionsSource || s.visibleWhen))
|
|
432
442
|
if (!wantsSource) {
|
|
433
|
-
return {}
|
|
443
|
+
return { isBoard }
|
|
434
444
|
}
|
|
435
445
|
const { status, loading } = useSetupStatus(props.appId, { setup: { steps: props.steps } })
|
|
436
|
-
return { setupStatus: status, setupStatusLoading: loading }
|
|
446
|
+
return { isBoard, setupStatus: status, setupStatusLoading: loading }
|
|
437
447
|
},
|
|
438
448
|
|
|
439
449
|
data() {
|
|
@@ -496,7 +506,7 @@ export default {
|
|
|
496
506
|
|
|
497
507
|
setupSteps() {
|
|
498
508
|
const skipped = new Set(this.skippedSteps.map((entry) => entry.step.id))
|
|
499
|
-
return this.declaredSteps.filter((s) => !skipped.has(s.id))
|
|
509
|
+
return this.declaredSteps.filter((s) => !skipped.has(s.id) && this.stepConditionHolds(s))
|
|
500
510
|
},
|
|
501
511
|
|
|
502
512
|
/**
|
|
@@ -793,6 +803,18 @@ export default {
|
|
|
793
803
|
return raw === '' ? '' : this.cnTranslate(raw)
|
|
794
804
|
},
|
|
795
805
|
|
|
806
|
+
/**
|
|
807
|
+
* The footnote under a choice step's options, from the step's `note`
|
|
808
|
+
* (or `footnote`), translated like the body.
|
|
809
|
+
*
|
|
810
|
+
* @param {object} step The step declaration.
|
|
811
|
+
* @return {string} The translated footnote, or ''.
|
|
812
|
+
*/
|
|
813
|
+
stepNote(step) {
|
|
814
|
+
const raw = (step && (step.note || step.footnote)) || ''
|
|
815
|
+
return raw === '' ? '' : this.cnTranslate(raw)
|
|
816
|
+
},
|
|
817
|
+
|
|
796
818
|
stepSlot(step) {
|
|
797
819
|
return 'step-' + step.id
|
|
798
820
|
},
|
|
@@ -847,6 +869,39 @@ export default {
|
|
|
847
869
|
})
|
|
848
870
|
},
|
|
849
871
|
|
|
872
|
+
/**
|
|
873
|
+
* Whether a step's `visibleWhen` holds: the value at that path in the
|
|
874
|
+
* setup status (`"flags.hasPayouts"`, dots walk into objects) is truthy,
|
|
875
|
+
* or equals `equals` when the step gives `{ path, equals }`. A step
|
|
876
|
+
* without `visibleWhen` always shows; one with it stays hidden until the
|
|
877
|
+
* status says so, also while the status loads (DqInstellen: the dwangsom
|
|
878
|
+
* step only when the app pays penalties).
|
|
879
|
+
*
|
|
880
|
+
* @param {object} step The step declaration.
|
|
881
|
+
* @return {boolean}
|
|
882
|
+
*/
|
|
883
|
+
stepConditionHolds(step) {
|
|
884
|
+
const when = step && step.visibleWhen
|
|
885
|
+
if (when === undefined || when === null || when === '') {
|
|
886
|
+
return true
|
|
887
|
+
}
|
|
888
|
+
const path = typeof when === 'string' ? when : when.path
|
|
889
|
+
if (typeof path !== 'string' || path === '') {
|
|
890
|
+
return true
|
|
891
|
+
}
|
|
892
|
+
let node = this.setupStatus
|
|
893
|
+
for (const key of path.split('.')) {
|
|
894
|
+
if (node === null || node === undefined || typeof node !== 'object') {
|
|
895
|
+
return false
|
|
896
|
+
}
|
|
897
|
+
node = node[key]
|
|
898
|
+
}
|
|
899
|
+
if (typeof when === 'object' && Object.hasOwn(when, 'equals')) {
|
|
900
|
+
return node === when.equals
|
|
901
|
+
}
|
|
902
|
+
return Boolean(node)
|
|
903
|
+
},
|
|
904
|
+
|
|
850
905
|
/**
|
|
851
906
|
* The option list a `choice` step declares `optionsSource` for, read
|
|
852
907
|
* from the setup status document the app already serves.
|
|
@@ -1338,6 +1393,18 @@ export default {
|
|
|
1338
1393
|
gap: 12px;
|
|
1339
1394
|
}
|
|
1340
1395
|
|
|
1396
|
+
.cn-setup-step__intro {
|
|
1397
|
+
margin: 0;
|
|
1398
|
+
font-size: 15px;
|
|
1399
|
+
line-height: 1.5;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
.cn-setup-step__note {
|
|
1403
|
+
margin: 0;
|
|
1404
|
+
font-size: 13px;
|
|
1405
|
+
color: var(--color-text-maxcontrast);
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1341
1408
|
.cn-setup-step__nav {
|
|
1342
1409
|
display: flex;
|
|
1343
1410
|
justify-content: flex-end;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import CnAuditTrailWidget from '../CnAuditTrailWidget/CnAuditTrailWidget.vue'
|
|
18
18
|
import CnBannerWidget from '../CnBannerWidget/CnBannerWidget.vue'
|
|
19
19
|
import CnDividerWidget from '../CnDividerWidget/CnDividerWidget.vue'
|
|
20
|
+
import CnExportsWidget from '../CnExportsWidget/CnExportsWidget.vue'
|
|
20
21
|
import CnHeaderWidget from '../CnHeaderWidget/CnHeaderWidget.vue'
|
|
21
22
|
import CnIntegrationWidget from '../CnIntegrationWidget/CnIntegrationWidget.vue'
|
|
22
23
|
import CnNavCardGrid from '../CnNavCardGrid/CnNavCardGrid.vue'
|
|
@@ -24,6 +25,7 @@ import CnObjectDataWidget from '../CnObjectDataWidget/CnObjectDataWidget.vue'
|
|
|
24
25
|
import CnObjectGeoWidget from '../CnObjectGeoWidget/CnObjectGeoWidget.vue'
|
|
25
26
|
import CnObjectMetadataWidget from '../CnObjectMetadataWidget/CnObjectMetadataWidget.vue'
|
|
26
27
|
import CnRelatedObjectsWidget from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue'
|
|
28
|
+
import CnSavedViewAlertWidget from '../CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue'
|
|
27
29
|
import CnTextWidget from '../CnTextWidget/CnTextWidget.vue'
|
|
28
30
|
import CnTimelineWidget from '../CnTimelineWidget/CnTimelineWidget.vue'
|
|
29
31
|
import CnWidgetCardGrid from '../CnWidgetCardGrid/CnWidgetCardGrid.vue'
|
|
@@ -89,4 +91,6 @@ export const BUILT_IN_WIDGETS = {
|
|
|
89
91
|
header: CnHeaderWidget,
|
|
90
92
|
text: CnTextWidget,
|
|
91
93
|
divider: CnDividerWidget,
|
|
94
|
+
'saved-view-alert': CnSavedViewAlertWidget,
|
|
95
|
+
exports: CnExportsWidget,
|
|
92
96
|
}
|
|
@@ -75,6 +75,7 @@ import '../CnTasksWidget/index.js'
|
|
|
75
75
|
import '../CnSectionsWidget/index.js'
|
|
76
76
|
import '../CnFactsWidget/index.js'
|
|
77
77
|
import '../CnDeviceFramesWidget/index.js'
|
|
78
|
+
import '../CnGroupedCardsWidget/index.js'
|
|
78
79
|
import '../CnChecklistRunWidget/index.js'
|
|
79
80
|
import '../CnWorkingCalendarWidget/index.js'
|
|
80
81
|
import '../CnPartyActionsWidget/index.js'
|
|
@@ -208,7 +208,7 @@ export default {
|
|
|
208
208
|
*/
|
|
209
209
|
dialogTitle: {
|
|
210
210
|
type: String,
|
|
211
|
-
default: 'Wizard',
|
|
211
|
+
default: () => t('nextcloud-vue', 'Wizard'),
|
|
212
212
|
},
|
|
213
213
|
|
|
214
214
|
/**
|
|
@@ -279,17 +279,17 @@ export default {
|
|
|
279
279
|
submitIcon: { type: [Object, Function], default: null },
|
|
280
280
|
|
|
281
281
|
/** Cancel-button label (wizard phase). */
|
|
282
|
-
cancelLabel: { type: String, default: 'Cancel' },
|
|
282
|
+
cancelLabel: { type: String, default: () => t('nextcloud-vue', 'Cancel') },
|
|
283
283
|
/** Back-button label. */
|
|
284
|
-
backLabel: { type: String, default: 'Back' },
|
|
284
|
+
backLabel: { type: String, default: () => t('nextcloud-vue', 'Back') },
|
|
285
285
|
/** Next-button label (intermediate steps). */
|
|
286
|
-
nextLabel: { type: String, default: 'Next' },
|
|
286
|
+
nextLabel: { type: String, default: () => t('nextcloud-vue', 'Next') },
|
|
287
287
|
/** Submit-button label (last step). */
|
|
288
|
-
submitLabel: { type: String, default: 'Submit' },
|
|
288
|
+
submitLabel: { type: String, default: () => t('nextcloud-vue', 'Submit') },
|
|
289
289
|
/** Close-button label (result phase). */
|
|
290
|
-
closeLabel: { type: String, default: 'Close' },
|
|
290
|
+
closeLabel: { type: String, default: () => t('nextcloud-vue', 'Close') },
|
|
291
291
|
/** Success banner default text when result.message is empty. */
|
|
292
|
-
successText: { type: String, default: 'Done.' },
|
|
292
|
+
successText: { type: String, default: () => t('nextcloud-vue', 'Done.') },
|
|
293
293
|
/**
|
|
294
294
|
* Whether the dialog can be dismissed (Cancel button, ESC, backdrop
|
|
295
295
|
* click) before reaching the result phase. `false` hides Cancel and
|
package/src/components/index.js
CHANGED
|
@@ -30,6 +30,8 @@ export { CnDateAxisView } from './CnDateAxisView/index.js'
|
|
|
30
30
|
export { CnObjectRow } from './CnObjectRow/index.js'
|
|
31
31
|
export { CnObjectList } from './CnObjectList/index.js'
|
|
32
32
|
export { CnOrderedListField } from './CnOrderedListField/index.js'
|
|
33
|
+
export { CnExportsWidget } from './CnExportsWidget/index.js'
|
|
34
|
+
export { CnSavedViewAlertWidget } from './CnSavedViewAlertWidget/index.js'
|
|
33
35
|
export { CnObjectKanban } from './CnObjectKanban/index.js'
|
|
34
36
|
export { CnObjectCalendar } from './CnObjectCalendar/index.js'
|
|
35
37
|
export { CnFolderTree } from './CnFolderTree/index.js'
|
|
@@ -224,6 +226,7 @@ export { CnTasksWidgetForm } from './CnTasksWidgetForm/index.js'
|
|
|
224
226
|
export { CnSectionsWidget } from './CnSectionsWidget/index.js'
|
|
225
227
|
export { CnFactsWidget } from './CnFactsWidget/index.js'
|
|
226
228
|
export { CnDeviceFramesWidget } from './CnDeviceFramesWidget/index.js'
|
|
229
|
+
export { CnGroupedCardsWidget } from './CnGroupedCardsWidget/index.js'
|
|
227
230
|
export { CnChecklistRunWidget } from './CnChecklistRunWidget/index.js'
|
|
228
231
|
export { CnWorkingCalendarWidget } from './CnWorkingCalendarWidget/index.js'
|
|
229
232
|
export { CnPartyActionsWidget } from './CnPartyActionsWidget/index.js'
|