@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
|
@@ -184,8 +184,14 @@
|
|
|
184
184
|
<CnIcon :name="widget.icon" :size="20" />
|
|
185
185
|
</template>
|
|
186
186
|
<!-- A renderer that reports its own header (`header` event:
|
|
187
|
-
`{ link, note }`, e.g. record-list's "3 in totaal"
|
|
188
|
-
|
|
187
|
+
`{ link, note, action, pill }`, e.g. record-list's "3 in totaal",
|
|
188
|
+
a facts card's status pill). -->
|
|
189
|
+
<template v-if="rendererHeader.note || rendererHeader.action || rendererHeader.pill" #actions>
|
|
190
|
+
<CnStatusBadge
|
|
191
|
+
v-if="rendererHeader.pill"
|
|
192
|
+
:label="rendererHeader.pill.label"
|
|
193
|
+
:variant="rendererHeader.pill.variant"
|
|
194
|
+
data-testid="cn-detail-widget-header-pill" />
|
|
189
195
|
<span
|
|
190
196
|
v-if="rendererHeader.note"
|
|
191
197
|
class="cn-detail-page__catalog-note"
|
|
@@ -298,6 +304,7 @@ import CnObjectDataWidget from '../CnObjectDataWidget/CnObjectDataWidget.vue'
|
|
|
298
304
|
import CnObjectFilesWidget from '../CnObjectFilesWidget/CnObjectFilesWidget.vue'
|
|
299
305
|
import CnObjectGeoWidget from '../CnObjectGeoWidget/CnObjectGeoWidget.vue'
|
|
300
306
|
import CnRelatedObjectsWidget from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue'
|
|
307
|
+
import CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'
|
|
301
308
|
import { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js'
|
|
302
309
|
import { normalizeLook } from '../../composables/useLook.js'
|
|
303
310
|
import { isAppInstalled } from '../../utils/appInstalled.js'
|
|
@@ -376,6 +383,7 @@ export default {
|
|
|
376
383
|
CnObjectDataWidget,
|
|
377
384
|
CnObjectGeoWidget,
|
|
378
385
|
CnRelatedObjectsWidget,
|
|
386
|
+
CnStatusBadge,
|
|
379
387
|
CnWidgetWrapper,
|
|
380
388
|
NcActionButton,
|
|
381
389
|
CnEmptyContent,
|
|
@@ -631,7 +639,7 @@ export default {
|
|
|
631
639
|
* `header` event (screens-relation-pages): a link and a note,
|
|
632
640
|
* with the list's total already filled in.
|
|
633
641
|
*/
|
|
634
|
-
rendererHeader: { link: null, note: '', action: null },
|
|
642
|
+
rendererHeader: { link: null, note: '', action: null, pill: null },
|
|
635
643
|
}
|
|
636
644
|
},
|
|
637
645
|
|
|
@@ -1218,7 +1226,8 @@ export default {
|
|
|
1218
1226
|
const link = header && header.link && typeof header.link === 'object' ? header.link : null
|
|
1219
1227
|
const note = header && typeof header.note === 'string' ? header.note : ''
|
|
1220
1228
|
const action = header && header.action && typeof header.action.run === 'function' && header.action.label ? header.action : null
|
|
1221
|
-
|
|
1229
|
+
const pill = header && header.pill && typeof header.pill.label === 'string' && header.pill.label !== '' ? header.pill : null
|
|
1230
|
+
this.rendererHeader = { link, note, action, pill }
|
|
1222
1231
|
},
|
|
1223
1232
|
|
|
1224
1233
|
/**
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
- SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
- SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
-->
|
|
5
|
+
<template>
|
|
6
|
+
<div class="cn-exports-widget" data-testid="cn-exports-widget">
|
|
7
|
+
<p v-if="loading && runs.length === 0" class="cn-exports-widget__muted">
|
|
8
|
+
{{ t('nextcloud-vue', 'Loading …') }}
|
|
9
|
+
</p>
|
|
10
|
+
<p v-else-if="failed" class="cn-exports-widget__muted" data-testid="cn-exports-error">
|
|
11
|
+
{{ t('nextcloud-vue', 'Your exports could not be loaded.') }}
|
|
12
|
+
</p>
|
|
13
|
+
<p v-else-if="runs.length === 0" class="cn-exports-widget__muted" data-testid="cn-exports-empty">
|
|
14
|
+
{{ emptyText }}
|
|
15
|
+
</p>
|
|
16
|
+
<ul v-else class="cn-exports-widget__list">
|
|
17
|
+
<li v-for="run in shownRuns"
|
|
18
|
+
:key="run.key"
|
|
19
|
+
class="cn-exports-widget__row"
|
|
20
|
+
data-testid="cn-exports-row">
|
|
21
|
+
<span class="cn-exports-widget__text">
|
|
22
|
+
<span class="cn-exports-widget__name">{{ run.filename }}</span>
|
|
23
|
+
<span class="cn-exports-widget__meta">{{ run.meta }}</span>
|
|
24
|
+
</span>
|
|
25
|
+
<span v-if="run.expiresToday" class="cn-exports-widget__tag" data-testid="cn-exports-expires-today">
|
|
26
|
+
{{ t('nextcloud-vue', 'Expires today') }}
|
|
27
|
+
</span>
|
|
28
|
+
<NcButton v-else-if="run.href"
|
|
29
|
+
:href="run.href"
|
|
30
|
+
data-testid="cn-exports-download">
|
|
31
|
+
{{ t('nextcloud-vue', 'Download') }}
|
|
32
|
+
</NcButton>
|
|
33
|
+
</li>
|
|
34
|
+
</ul>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script>
|
|
39
|
+
import { getCurrentUser } from '@nextcloud/auth'
|
|
40
|
+
import axios from '@nextcloud/axios'
|
|
41
|
+
import { translatePlural as n, translate as t } from '@nextcloud/l10n'
|
|
42
|
+
import { generateRemoteUrl, generateUrl } from '@nextcloud/router'
|
|
43
|
+
import { NcButton } from '@nextcloud/vue'
|
|
44
|
+
import { formatBoardDate } from '../../utils/boardDate.js'
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* CnExportsWidget — the reader's own exports (DqZoekresultaten "Uw exports"):
|
|
48
|
+
* each file with when it was made, how often it was downloaded and when it
|
|
49
|
+
* expires, a Download button while the file is there, and "Expires today" on
|
|
50
|
+
* the day it goes.
|
|
51
|
+
*
|
|
52
|
+
* Reads OpenRegister's export runs (`GET /apps/openregister/api/exports`)
|
|
53
|
+
* with the reader as the actor, so an administrator sees their own here too.
|
|
54
|
+
* `content.register` and `content.schema` narrow it to one list's exports.
|
|
55
|
+
* A run whose file was swept, or that never produced one, is left out.
|
|
56
|
+
*
|
|
57
|
+
* Example (manifest, in an index page's `sidePanel`):
|
|
58
|
+
* ```json
|
|
59
|
+
* { "id": "exports", "type": "exports", "title": "Your exports", "content": { "register": "dossiq", "schema": "case", "limit": 5 } }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export default {
|
|
63
|
+
name: 'CnExportsWidget',
|
|
64
|
+
|
|
65
|
+
components: { NcButton },
|
|
66
|
+
|
|
67
|
+
inject: {
|
|
68
|
+
/** Host translate function provided by CnAppRoot. */
|
|
69
|
+
cnTranslate: { default: () => (key) => key },
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
props: {
|
|
73
|
+
/** `{ register?, schema?, limit?, emptyText? }`; `limit` defaults to 5. */
|
|
74
|
+
content: {
|
|
75
|
+
type: Object,
|
|
76
|
+
default: () => ({}),
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
data() {
|
|
81
|
+
return { loading: false, failed: false, runs: [], now: new Date() }
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
computed: {
|
|
85
|
+
/** @return {number} How many exports to show. */
|
|
86
|
+
limit() {
|
|
87
|
+
const limit = Number(this.content && this.content.limit)
|
|
88
|
+
return Number.isInteger(limit) && limit > 0 ? limit : 5
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/** @return {Array<object>} The exports to draw, newest first. */
|
|
92
|
+
shownRuns() {
|
|
93
|
+
return this.runs
|
|
94
|
+
.filter((run) => run && run.filename && run.fileId !== null && run.fileId !== undefined && run.status !== 'expired')
|
|
95
|
+
.slice(0, this.limit)
|
|
96
|
+
.map((run) => this.view(run))
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/** @return {string} The empty line. */
|
|
100
|
+
emptyText() {
|
|
101
|
+
const own = this.content && this.content.emptyText
|
|
102
|
+
return own ? this.cnTranslate(own) : t('nextcloud-vue', 'You have no exports here.')
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
mounted() {
|
|
107
|
+
this.load()
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
methods: {
|
|
111
|
+
t,
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Read the reader's export runs.
|
|
115
|
+
*
|
|
116
|
+
* @return {Promise<void>}
|
|
117
|
+
*/
|
|
118
|
+
async load() {
|
|
119
|
+
const user = getCurrentUser()
|
|
120
|
+
if (!user || !user.uid) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
this.loading = true
|
|
124
|
+
this.failed = false
|
|
125
|
+
try {
|
|
126
|
+
const params = { actor: user.uid, limit: Math.max(this.limit * 2, 10) }
|
|
127
|
+
for (const key of ['register', 'schema']) {
|
|
128
|
+
if (this.content && typeof this.content[key] === 'string' && this.content[key] !== '') {
|
|
129
|
+
params[key] = this.content[key]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const response = await axios.get(generateUrl('/apps/openregister/api/exports'), { params })
|
|
133
|
+
const results = response && response.data && Array.isArray(response.data.results) ? response.data.results : []
|
|
134
|
+
this.runs = [...results].sort((a, b) => String(b.producedAt || b.created || '').localeCompare(String(a.producedAt || a.created || '')))
|
|
135
|
+
} catch {
|
|
136
|
+
this.failed = true
|
|
137
|
+
this.runs = []
|
|
138
|
+
} finally {
|
|
139
|
+
this.loading = false
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* One export as the list draws it.
|
|
145
|
+
*
|
|
146
|
+
* @param {object} run An export run.
|
|
147
|
+
* @return {{key: string, filename: string, meta: string, href: string, expiresToday: boolean}}
|
|
148
|
+
*/
|
|
149
|
+
view(run) {
|
|
150
|
+
const made = run.producedAt || run.created
|
|
151
|
+
const parts = []
|
|
152
|
+
if (made) {
|
|
153
|
+
parts.push(t('nextcloud-vue', 'Made {date}', { date: formatBoardDate(made, this.now) }))
|
|
154
|
+
}
|
|
155
|
+
if (typeof run.downloadCount === 'number') {
|
|
156
|
+
parts.push(n('nextcloud-vue', 'downloaded %n time', 'downloaded %n times', run.downloadCount))
|
|
157
|
+
}
|
|
158
|
+
if (run.expiresAt) {
|
|
159
|
+
parts.push(t('nextcloud-vue', 'expires {date}', { date: formatBoardDate(run.expiresAt, this.now) }))
|
|
160
|
+
}
|
|
161
|
+
const user = getCurrentUser()
|
|
162
|
+
const href = run.filePath && user && user.uid
|
|
163
|
+
? generateRemoteUrl(`dav/files/${encodeURIComponent(user.uid)}`) + String(run.filePath).split('/').map(encodeURIComponent).join('/')
|
|
164
|
+
: ''
|
|
165
|
+
return {
|
|
166
|
+
key: String(run.uuid || run.id),
|
|
167
|
+
filename: run.filename,
|
|
168
|
+
meta: parts.join(' · '),
|
|
169
|
+
href,
|
|
170
|
+
expiresToday: Boolean(run.expiresAt) && new Date(run.expiresAt).toDateString() === this.now.toDateString(),
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
</script>
|
|
176
|
+
|
|
177
|
+
<style scoped>
|
|
178
|
+
.cn-exports-widget__list {
|
|
179
|
+
display: flex;
|
|
180
|
+
flex-direction: column;
|
|
181
|
+
margin: 0;
|
|
182
|
+
padding: 0;
|
|
183
|
+
list-style: none;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.cn-exports-widget__row {
|
|
187
|
+
display: flex;
|
|
188
|
+
align-items: center;
|
|
189
|
+
gap: 12px;
|
|
190
|
+
padding: 10px 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.cn-exports-widget__row + .cn-exports-widget__row {
|
|
194
|
+
border-top: 1px solid var(--color-border);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.cn-exports-widget__text {
|
|
198
|
+
display: flex;
|
|
199
|
+
flex: 1;
|
|
200
|
+
flex-direction: column;
|
|
201
|
+
gap: 2px;
|
|
202
|
+
min-width: 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.cn-exports-widget__name {
|
|
206
|
+
overflow: hidden;
|
|
207
|
+
font-size: 14px;
|
|
208
|
+
font-weight: 600;
|
|
209
|
+
text-overflow: ellipsis;
|
|
210
|
+
white-space: nowrap;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.cn-exports-widget__meta,
|
|
214
|
+
.cn-exports-widget__muted {
|
|
215
|
+
color: var(--color-text-maxcontrast);
|
|
216
|
+
font-size: 13px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.cn-exports-widget__muted {
|
|
220
|
+
margin: 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.cn-exports-widget__tag {
|
|
224
|
+
flex: none;
|
|
225
|
+
padding: 3px 10px;
|
|
226
|
+
border-radius: 12px;
|
|
227
|
+
background: var(--color-warning-light, color-mix(in srgb, var(--color-warning) 18%, transparent));
|
|
228
|
+
color: var(--color-warning-text, var(--color-main-text));
|
|
229
|
+
font-size: 13px;
|
|
230
|
+
font-weight: 600;
|
|
231
|
+
white-space: nowrap;
|
|
232
|
+
}
|
|
233
|
+
</style>
|
|
@@ -132,6 +132,13 @@
|
|
|
132
132
|
</div>
|
|
133
133
|
</template>
|
|
134
134
|
</template>
|
|
135
|
+
<NcNoteCard
|
|
136
|
+
v-if="notice && record"
|
|
137
|
+
:type="notice.type"
|
|
138
|
+
class="cn-facts-widget__notice"
|
|
139
|
+
data-testid="cn-facts-notice">
|
|
140
|
+
{{ notice.text }}
|
|
141
|
+
</NcNoteCard>
|
|
135
142
|
<component
|
|
136
143
|
:is="link.to ? 'router-link' : 'a'"
|
|
137
144
|
v-if="link && record"
|
|
@@ -157,7 +164,7 @@
|
|
|
157
164
|
import { emit } from '@nextcloud/event-bus'
|
|
158
165
|
import { formatFileSize } from '@nextcloud/files'
|
|
159
166
|
import { translate as t } from '@nextcloud/l10n'
|
|
160
|
-
import { NcLoadingIcon } from '@nextcloud/vue'
|
|
167
|
+
import { NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'
|
|
161
168
|
import Check from 'vue-material-design-icons/Check.vue'
|
|
162
169
|
import ContentCopy from 'vue-material-design-icons/ContentCopy.vue'
|
|
163
170
|
import EyeOutline from 'vue-material-design-icons/EyeOutline.vue'
|
|
@@ -266,7 +273,7 @@ export const FACTS_REVEAL_CHANNEL = 'cn:facts:reveal'
|
|
|
266
273
|
export default {
|
|
267
274
|
name: 'CnFactsWidget',
|
|
268
275
|
|
|
269
|
-
components: { Check, CnIcon, CnStatusBadge, ContentCopy, EyeOutline, NcLoadingIcon },
|
|
276
|
+
components: { Check, CnIcon, CnStatusBadge, ContentCopy, EyeOutline, NcLoadingIcon, NcNoteCard },
|
|
270
277
|
|
|
271
278
|
inject: {
|
|
272
279
|
cnTranslate: { default: () => (key) => key },
|
|
@@ -290,6 +297,8 @@ export default {
|
|
|
290
297
|
* `resolve: { register, schema, labelField? }` on an entry or a part turns a value that is a reference (an id, or a list of ids) into the label of the referenced object (`labelField`, else `title`, then `name`): the case type or status of a task shows its name, not its uuid. The ids are fetched once per register and schema through the object store and shared by every facts widget on the page; the entry stays empty until its label is known, and when no label can be read. A resolved value works as a pill too: `map` is applied to the resolved label, and `variantMap` / `colorMap` look the tone up by the value of `resolve.toneField` on the referenced object when that is set (a status named by its `name`, coloured by its `state`), then by the resolved label, then by the stored value.
|
|
291
298
|
* `format: 'user'` shows a Nextcloud user id as the user's display name, read once per id; the entry stays empty until the name is known.
|
|
292
299
|
* - `action` — an action drawn as a button under the facts; `headerAction` — one drawn in the card header (reported through the `header` event).
|
|
300
|
+
* - `headerPill` — a status pill in the card header (reported through the `header` event): `{ path?, text?, map?, variant?, variantMap?, colorMap? }`, read from the record like a `pill` entry (DqBezwaar "Advies ontvangen"); nothing shows while the value is empty.
|
|
301
|
+
* - `notice` — `{ text, variant? }`, a note band inside the card under the facts (`info` by default; `success`, `warning` or `error`); the text is translated.
|
|
293
302
|
* `format` is `text` (default), `date` (board short date), `date-long` (always with the year), `list` (an array joined by ", ", each item read at `itemPath`), `bytes` (a size, "1.5 MB") or `currency` (a money amount in the reader's language, "€ 1.234,50": the code in `currency`, else the record's `currencyField`, else the app's reporting currency, else EUR; `decimals` defaults to 2).
|
|
294
303
|
* `map` turns a raw value into a label (translated). `parts` (on a `line`) lists paths, or `{ path, label?, format? }`, joined by `separator` (default " · "); empty parts are dropped.
|
|
295
304
|
* - `source` — `{ register, schema, id }` or `{ url }`; omitted = the current object. An entry with `from: "object"` reads the current object even then (a client card that also shows the ticket's channel).
|
|
@@ -508,6 +517,47 @@ export default {
|
|
|
508
517
|
return this.actionView(this.content?.headerAction)
|
|
509
518
|
},
|
|
510
519
|
|
|
520
|
+
/**
|
|
521
|
+
* The card header's status pill, read from the record like a `pill`
|
|
522
|
+
* entry, or null when it has no text.
|
|
523
|
+
*
|
|
524
|
+
* @return {{label: string, variant: string}|null}
|
|
525
|
+
*/
|
|
526
|
+
headerPill() {
|
|
527
|
+
const pill = this.content?.headerPill
|
|
528
|
+
if (!pill || typeof pill !== 'object' || !this.record) {
|
|
529
|
+
return null
|
|
530
|
+
}
|
|
531
|
+
const raw = typeof pill.path === 'string' && pill.path !== '' ? readPath(this.record, pill.path) : undefined
|
|
532
|
+
const mapped = pill.map && (typeof raw === 'string' || typeof raw === 'number') && Object.hasOwn(pill.map, raw) ? pill.map[raw] : undefined
|
|
533
|
+
const text = mapped ?? pill.text ?? raw
|
|
534
|
+
if (typeof text !== 'string' && typeof text !== 'number') {
|
|
535
|
+
return null
|
|
536
|
+
}
|
|
537
|
+
const label = this.tr(String(text))
|
|
538
|
+
if (label === '') {
|
|
539
|
+
return null
|
|
540
|
+
}
|
|
541
|
+
const colours = pill.variantMap || pill.colorMap
|
|
542
|
+
const hit = colours && (typeof raw === 'string' || typeof raw === 'number') && Object.hasOwn(colours, raw) ? colours[raw] : pill.variant
|
|
543
|
+
return { label, variant: isBadgeVariant(hit) ? hit : 'default' }
|
|
544
|
+
},
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* The note band under the facts: its text translated, its NcNoteCard
|
|
548
|
+
* type from `variant` (info by default), or null without text.
|
|
549
|
+
*
|
|
550
|
+
* @return {{text: string, type: string}|null}
|
|
551
|
+
*/
|
|
552
|
+
notice() {
|
|
553
|
+
const notice = this.content?.notice
|
|
554
|
+
const text = notice && typeof notice.text === 'string' ? this.tr(notice.text) : ''
|
|
555
|
+
if (text === '') {
|
|
556
|
+
return null
|
|
557
|
+
}
|
|
558
|
+
return { text, type: ['success', 'warning', 'error'].includes(notice.variant) ? notice.variant : 'info' }
|
|
559
|
+
},
|
|
560
|
+
|
|
511
561
|
/** @return {string} The reveal button's text. */
|
|
512
562
|
showLabel() {
|
|
513
563
|
return t('nextcloud-vue', 'Show')
|
|
@@ -544,6 +594,13 @@ export default {
|
|
|
544
594
|
this.emitHeader()
|
|
545
595
|
},
|
|
546
596
|
},
|
|
597
|
+
|
|
598
|
+
headerPill: {
|
|
599
|
+
deep: true,
|
|
600
|
+
handler() {
|
|
601
|
+
this.emitHeader()
|
|
602
|
+
},
|
|
603
|
+
},
|
|
547
604
|
},
|
|
548
605
|
|
|
549
606
|
methods: {
|
|
@@ -803,12 +860,13 @@ export default {
|
|
|
803
860
|
const view = this.headerAction
|
|
804
861
|
/**
|
|
805
862
|
* @event header Emitted with the card header's parts: the header action, if any.
|
|
806
|
-
* @type {{link: null, note: string, action: (object|null)}} `action` is `{ label, icon, run }`.
|
|
863
|
+
* @type {{link: null, note: string, action: (object|null), pill: (object|null)}} `action` is `{ label, icon, run }`, `pill` is `{ label, variant }`.
|
|
807
864
|
*/
|
|
808
865
|
this.$emit('header', {
|
|
809
866
|
link: null,
|
|
810
867
|
note: '',
|
|
811
868
|
action: view ? { ...view, run: () => this.runAction(this.content.headerAction) } : null,
|
|
869
|
+
pill: this.headerPill,
|
|
812
870
|
})
|
|
813
871
|
},
|
|
814
872
|
|
|
@@ -1368,6 +1426,10 @@ export default {
|
|
|
1368
1426
|
background: var(--color-primary-element-light-hover, var(--color-primary-element-light));
|
|
1369
1427
|
}
|
|
1370
1428
|
|
|
1429
|
+
.cn-facts-widget__notice {
|
|
1430
|
+
margin: 4px 0 0;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1371
1433
|
.cn-facts-widget__link {
|
|
1372
1434
|
font-size: 14px;
|
|
1373
1435
|
font-weight: 600;
|