@conduction/nextcloud-vue 2.104.0 → 2.106.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.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +18 -0
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +3 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +18 -0
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +93 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +6 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +3 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +112 -5
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +9 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js +24 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js +49 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +36 -18
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +17 -38
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +2 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +32 -29
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +53 -2
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +119 -111
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +62 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +73 -4
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +74 -27
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +208 -46
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +121 -98
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +24 -0
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +20 -4
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +25 -6
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +112 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +100 -44
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +67 -4
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js +9 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js.map +1 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js +88 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js +39 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +295 -12
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +267 -144
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +4 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +3 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +93 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +322 -246
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue.js +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +122 -7
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js +189 -93
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +3 -3
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +16 -4
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue.js +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +42 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +38 -19
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js +9 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js.map +1 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js +258 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js +69 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +11 -0
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +4 -4
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +16 -14
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +24 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +24 -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 +1369 -748
- package/dist/esm/utils/dueText.js +18 -3
- package/dist/esm/utils/dueText.js.map +1 -1
- package/dist/esm/utils/libraryWidgetKeys.js +2 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/nextcloudApps.js +45 -0
- package/dist/esm/utils/nextcloudApps.js.map +1 -0
- package/dist/esm/utils/scopeListLayout.js +9 -2
- package/dist/esm/utils/scopeListLayout.js.map +1 -1
- package/dist/esm/utils/sortOrder.js +11 -1
- package/dist/esm/utils/sortOrder.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/visibleWhen.js +12 -4
- package/dist/esm/utils/visibleWhen.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +8965 -6497
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1369 -748
- package/l10n/en.json +24 -1
- package/l10n/nl.json +24 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -1
- package/src/components/CnCardGrid/CnCardGrid.md +2 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +20 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +19 -1
- package/src/components/CnChartWidget/CnChartWidget.md +2 -0
- package/src/components/CnChartWidget/CnChartWidget.vue +93 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -6
- package/src/components/CnDetailPage/CnDetailPage.md +3 -2
- package/src/components/CnDetailPage/CnDetailPage.vue +112 -5
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +60 -0
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +36 -29
- package/src/components/CnFactsWidget/CnFactsWidget.vue +4 -0
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -1
- package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +4 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +70 -4
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +62 -1
- package/src/components/CnFlowsPage/CnFlowBoard.vue +132 -8
- package/src/components/CnIndexPage/CnIndexPage.md +8 -5
- package/src/components/CnIndexPage/CnIndexPage.vue +236 -54
- package/src/components/CnIndexPage/CnIndexPageWidgets.vue +36 -1
- package/src/components/CnIndexPage/useSelfFetchList.js +25 -6
- package/src/components/CnIndexSidebar/CnIndexSidebar.md +2 -0
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +148 -1
- package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +68 -5
- package/src/components/CnNoticeWidget/CnNoticeWidget.vue +153 -0
- package/src/components/CnNoticeWidget/index.js +12 -0
- package/src/components/CnObjectCard/CnObjectCard.md +1 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +354 -13
- package/src/components/CnObjectSidebar/CnFilesTab.vue +6 -0
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +190 -4
- package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +209 -9
- package/src/components/CnSettingsField/CnSettingsField.vue +4 -1
- package/src/components/CnSetupWizard/CnSetupWizard.vue +9 -1
- package/src/components/CnTabs/CnTabs.vue +11 -0
- package/src/components/CnTabsWidget/CnTabsWidget.vue +91 -18
- package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.md +11 -0
- package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue +382 -0
- package/src/components/CnTeamWorkloadWidget/index.js +14 -0
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +15 -4
- package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
- package/src/components/index.js +2 -0
- package/src/css/dialog.css +20 -2
- package/src/css/index-page.css +14 -2
- package/src/css/look-board-detail.css +125 -8
- package/src/css/look-board-index.css +100 -4
- package/src/css/look-board.css +122 -14
- package/src/index.js +2 -1
- package/src/schemas/app-manifest-v2.schema.json +110 -8
- package/src/utils/dueText.js +18 -3
- package/src/utils/libraryWidgetKeys.js +2 -0
- package/src/utils/nextcloudApps.js +50 -0
- package/src/utils/scopeListLayout.js +9 -2
- package/src/utils/sortOrder.js +10 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/visibleWhen.js +12 -4
|
@@ -15,8 +15,61 @@
|
|
|
15
15
|
@update:modelValue="$emit('select', object)" />
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
+
<!-- Board look, record layout (`layout`): head pill and number, title,
|
|
19
|
+
meta line, then a footer with a pill and a date. -->
|
|
20
|
+
<div v-if="recordLayout" class="cn-object-card__content cn-object-card__record" data-testid="cn-object-card-record">
|
|
21
|
+
<div class="cn-object-card__record-head">
|
|
22
|
+
<CnStatusBadge
|
|
23
|
+
v-if="recordHeadPill"
|
|
24
|
+
class="cn-object-card__record-pill"
|
|
25
|
+
:label="recordHeadPill.label"
|
|
26
|
+
:variant="recordHeadPill.variant"
|
|
27
|
+
data-testid="cn-object-card-head-pill" />
|
|
28
|
+
<span v-if="recordNumber" class="cn-object-card__record-number" data-testid="cn-object-card-number">{{ recordNumber }}</span>
|
|
29
|
+
<div
|
|
30
|
+
v-if="$slots.actions"
|
|
31
|
+
class="cn-object-card__menu"
|
|
32
|
+
@click.stop
|
|
33
|
+
@auxclick.stop>
|
|
34
|
+
<slot name="actions" :object="object" />
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
<h3 class="cn-object-card__title">
|
|
38
|
+
<CnLockIndicator :object="object" :size="16" />
|
|
39
|
+
{{ recordTitle }}
|
|
40
|
+
</h3>
|
|
41
|
+
<!-- A part whose field names a page column with a widget draws through
|
|
42
|
+
it, as its table cell does; the rest are text. -->
|
|
43
|
+
<p v-if="recordMetaParts.length > 0" class="cn-object-card__record-meta" data-testid="cn-object-card-meta">
|
|
44
|
+
<template v-for="(part, index) in recordMetaParts" :key="part.field">
|
|
45
|
+
<span v-if="index > 0" aria-hidden="true"> · </span>
|
|
46
|
+
<CnCellRenderer
|
|
47
|
+
v-if="part.column && part.column.widget"
|
|
48
|
+
:value="part.value"
|
|
49
|
+
:widget="part.column.widget"
|
|
50
|
+
:widgetProps="part.column.widgetProps || undefined"
|
|
51
|
+
:formatter="part.column.formatter || null"
|
|
52
|
+
:formatterOptions="part.column.formatterOptions || null"
|
|
53
|
+
:row="object" />
|
|
54
|
+
<span v-else>{{ part.text }}</span>
|
|
55
|
+
</template>
|
|
56
|
+
</p>
|
|
57
|
+
<div v-if="$slots.badges" class="cn-object-card__badges">
|
|
58
|
+
<slot name="badges" :object="object" />
|
|
59
|
+
</div>
|
|
60
|
+
<div v-if="recordFootPill || recordDate" class="cn-object-card__record-foot" data-testid="cn-object-card-foot">
|
|
61
|
+
<CnStatusBadge
|
|
62
|
+
v-if="recordFootPill"
|
|
63
|
+
class="cn-object-card__record-pill"
|
|
64
|
+
:label="recordFootPill.label"
|
|
65
|
+
:variant="recordFootPill.variant"
|
|
66
|
+
data-testid="cn-object-card-foot-pill" />
|
|
67
|
+
<span v-if="recordDate" class="cn-object-card__record-date" data-testid="cn-object-card-date">{{ recordDate }}</span>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
18
71
|
<!-- Card content -->
|
|
19
|
-
<div class="cn-object-card__content">
|
|
72
|
+
<div v-else class="cn-object-card__content">
|
|
20
73
|
<!-- Header: image + title -->
|
|
21
74
|
<div class="cn-object-card__header">
|
|
22
75
|
<!-- Board look: the leading element, initials in a circle or an icon on a tint. -->
|
|
@@ -92,6 +145,11 @@
|
|
|
92
145
|
<CnCellRenderer
|
|
93
146
|
:value="field.value"
|
|
94
147
|
:property="field.property"
|
|
148
|
+
:formatter="field.column && field.column.formatter || null"
|
|
149
|
+
:formatterOptions="field.column && field.column.formatterOptions || null"
|
|
150
|
+
:widget="field.column && field.column.widget || null"
|
|
151
|
+
:widgetProps="field.column && field.column.widgetProps || undefined"
|
|
152
|
+
:row="object"
|
|
95
153
|
:truncate="60" />
|
|
96
154
|
</div>
|
|
97
155
|
</slot>
|
|
@@ -127,9 +185,15 @@
|
|
|
127
185
|
</template>
|
|
128
186
|
|
|
129
187
|
<script>
|
|
188
|
+
import { translate as t } from '@nextcloud/l10n'
|
|
130
189
|
import { NcButton, NcCheckboxRadioSwitch } from '@nextcloud/vue'
|
|
131
190
|
import { useClickDragGuard } from '../../composables/useClickDragGuard.js'
|
|
132
191
|
import { normalizeLook } from '../../composables/useLook.js'
|
|
192
|
+
import { isBadgeVariant } from '../../utils/badgeVariants.js'
|
|
193
|
+
import { formatBoardDate } from '../../utils/boardDate.js'
|
|
194
|
+
import { resolveDateVariant } from '../../utils/dateVariant.js'
|
|
195
|
+
import { resolveDue } from '../../utils/dueText.js'
|
|
196
|
+
import { readPath } from '../../utils/readPath.js'
|
|
133
197
|
import { resolveImageUrl } from '../../utils/resolveImageUrl.js'
|
|
134
198
|
import { isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'
|
|
135
199
|
import { formatValue } from '../../utils/schema.js'
|
|
@@ -178,6 +242,8 @@ export default {
|
|
|
178
242
|
cnTranslate: { default: () => (key) => key },
|
|
179
243
|
/** The look CnAppRoot provides; `board` draws the record card of the screens. */
|
|
180
244
|
cnLook: { default: 'nextcloud' },
|
|
245
|
+
/** The cell formatters CnAppRoot provides, for a layout part whose page column names one. */
|
|
246
|
+
cnFormatters: { default: () => ({}) },
|
|
181
247
|
},
|
|
182
248
|
|
|
183
249
|
props: {
|
|
@@ -270,6 +336,25 @@ export default {
|
|
|
270
336
|
default: null,
|
|
271
337
|
},
|
|
272
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Board look: the record layout (manifest key `config.cardLayout`).
|
|
341
|
+
* Every part names a field of the object (a dot path) and is left out
|
|
342
|
+
* while that field is empty:
|
|
343
|
+
* `{ headPill, number, title, meta, footerPill, footerDate }`.
|
|
344
|
+
* A pill is `{ field, colorMap?, labels?, variant? }`: `colorMap` maps a
|
|
345
|
+
* value to a CnStatusBadge variant (ignoring case), `labels` a value to
|
|
346
|
+
* the text shown. `meta` is a list of fields, joined with " · ".
|
|
347
|
+
* `footerDate` is `{ field, label? }`, drawn as "Termijn 5 okt".
|
|
348
|
+
* Without it the card keeps its head, facts and action.
|
|
349
|
+
*
|
|
350
|
+
* @type {{headPill?: object, number?: string, title?: string, meta?: Array<string>, footerPill?: object, footerDate?: {field: string, label?: string}}}
|
|
351
|
+
* @spec openspec/changes/board-record-card-layout/specs/board-record-card-layout/spec.md#requirement-a-board-card-can-draw-the-record-layout-from-config
|
|
352
|
+
*/
|
|
353
|
+
layout: {
|
|
354
|
+
type: Object,
|
|
355
|
+
default: null,
|
|
356
|
+
},
|
|
357
|
+
|
|
273
358
|
/**
|
|
274
359
|
* The property keys the facts list shows, in order (manifest key
|
|
275
360
|
* `config.cardFields`). Without it the card shows the first
|
|
@@ -282,6 +367,17 @@ export default {
|
|
|
282
367
|
default: null,
|
|
283
368
|
},
|
|
284
369
|
|
|
370
|
+
/**
|
|
371
|
+
* The page's columns by key: a fact whose key names a column renders
|
|
372
|
+
* through that column's label, formatter and widget, as the table does.
|
|
373
|
+
*
|
|
374
|
+
* @type {object}
|
|
375
|
+
*/
|
|
376
|
+
cardFieldColumns: {
|
|
377
|
+
type: Object,
|
|
378
|
+
default: null,
|
|
379
|
+
},
|
|
380
|
+
|
|
285
381
|
/** Maximum number of metadata fields to show */
|
|
286
382
|
maxMetadata: {
|
|
287
383
|
type: Number,
|
|
@@ -333,6 +429,92 @@ export default {
|
|
|
333
429
|
return null
|
|
334
430
|
},
|
|
335
431
|
|
|
432
|
+
/**
|
|
433
|
+
* The record layout when the board look draws it, else null.
|
|
434
|
+
*
|
|
435
|
+
* @return {?object}
|
|
436
|
+
* @spec openspec/changes/board-record-card-layout/specs/board-record-card-layout/spec.md#requirement-a-board-card-can-draw-the-record-layout-from-config
|
|
437
|
+
*/
|
|
438
|
+
recordLayout() {
|
|
439
|
+
return this.isBoardLook && this.layout && typeof this.layout === 'object' ? this.layout : null
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* The record layout's head pill, or null.
|
|
444
|
+
*
|
|
445
|
+
* @return {?{label: string, variant: string}}
|
|
446
|
+
*/
|
|
447
|
+
recordHeadPill() {
|
|
448
|
+
return this.recordLayout ? this.layoutPill(this.recordLayout.headPill) : null
|
|
449
|
+
},
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* The record layout's footer pill, or null.
|
|
453
|
+
*
|
|
454
|
+
* @return {?{label: string, variant: string}}
|
|
455
|
+
*/
|
|
456
|
+
recordFootPill() {
|
|
457
|
+
return this.recordLayout ? this.layoutPill(this.recordLayout.footerPill) : null
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* The record number at the end of the head, or ''.
|
|
462
|
+
*
|
|
463
|
+
* @return {string}
|
|
464
|
+
*/
|
|
465
|
+
recordNumber() {
|
|
466
|
+
return this.recordLayout ? this.layoutText(this.recordLayout.number) : ''
|
|
467
|
+
},
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* The title: the layout's `title` field, else the card's own title.
|
|
471
|
+
*
|
|
472
|
+
* @return {string}
|
|
473
|
+
*/
|
|
474
|
+
recordTitle() {
|
|
475
|
+
const text = this.recordLayout ? this.layoutText(this.recordLayout.title) : ''
|
|
476
|
+
return text !== '' ? text : this.title
|
|
477
|
+
},
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* The meta line: the layout's `meta` fields that hold a value, joined.
|
|
481
|
+
*
|
|
482
|
+
* @return {string}
|
|
483
|
+
*/
|
|
484
|
+
recordMeta() {
|
|
485
|
+
return this.recordMetaParts.map((part) => part.text).join(' · ')
|
|
486
|
+
},
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* The meta line's parts that hold a value: each with its text and, when
|
|
490
|
+
* its field names a page column, that column (whose widget draws it).
|
|
491
|
+
*
|
|
492
|
+
* @return {Array<{field: string, value: unknown, text: string, column: ?object}>}
|
|
493
|
+
*/
|
|
494
|
+
recordMetaParts() {
|
|
495
|
+
const fields = this.recordLayout && Array.isArray(this.recordLayout.meta) ? this.recordLayout.meta : []
|
|
496
|
+
return fields
|
|
497
|
+
.map((part) => this.metaPart(part))
|
|
498
|
+
.filter((part) => part !== null && part.text !== '')
|
|
499
|
+
},
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* The footer date with its label ("Termijn 5 okt"), or ''.
|
|
503
|
+
*
|
|
504
|
+
* @return {string}
|
|
505
|
+
*/
|
|
506
|
+
recordDate() {
|
|
507
|
+
const def = this.recordLayout ? this.recordLayout.footerDate : null
|
|
508
|
+
if (!def || typeof def.field !== 'string') {
|
|
509
|
+
return ''
|
|
510
|
+
}
|
|
511
|
+
const date = formatBoardDate(readPath(this.object, def.field))
|
|
512
|
+
if (date === '') {
|
|
513
|
+
return ''
|
|
514
|
+
}
|
|
515
|
+
return typeof def.label === 'string' && def.label !== '' ? `${this.cnTranslate(def.label)} ${date}` : date
|
|
516
|
+
},
|
|
517
|
+
|
|
336
518
|
/**
|
|
337
519
|
* The accent variant when it is a known one, else ''.
|
|
338
520
|
*
|
|
@@ -401,12 +583,7 @@ export default {
|
|
|
401
583
|
if (Array.isArray(this.cardFields)) {
|
|
402
584
|
return this.cardFields
|
|
403
585
|
.filter((key) => typeof key === 'string' && this.schema.properties[key] && !this.configFields.includes(key))
|
|
404
|
-
.map((key) => (
|
|
405
|
-
key,
|
|
406
|
-
label: this.cnTranslate(this.schema.properties[key].title || key),
|
|
407
|
-
value: this.object[key],
|
|
408
|
-
property: this.schema.properties[key],
|
|
409
|
-
}))
|
|
586
|
+
.map((key) => this.metadataField(key, this.schema.properties[key]))
|
|
410
587
|
}
|
|
411
588
|
|
|
412
589
|
return Object.entries(this.schema.properties)
|
|
@@ -431,16 +608,180 @@ export default {
|
|
|
431
608
|
return orderA - orderB
|
|
432
609
|
})
|
|
433
610
|
.slice(0, this.maxMetadata)
|
|
434
|
-
.map(([key, prop]) => (
|
|
435
|
-
key,
|
|
436
|
-
label: this.cnTranslate(prop.title || key),
|
|
437
|
-
value: this.object[key],
|
|
438
|
-
property: prop,
|
|
439
|
-
}))
|
|
611
|
+
.map(([key, prop]) => this.metadataField(key, prop))
|
|
440
612
|
},
|
|
441
613
|
},
|
|
442
614
|
|
|
443
615
|
methods: {
|
|
616
|
+
/**
|
|
617
|
+
* One meta part: a field name reads through the page column it names;
|
|
618
|
+
* `{ field, formatter?, formatterOptions? }` reads as plain text through
|
|
619
|
+
* its own formatter, so a column's widget (a badge) stays in the table.
|
|
620
|
+
*
|
|
621
|
+
* @param {string|{field: string, formatter?: string, formatterOptions?: object}} part The part.
|
|
622
|
+
* @return {?{field: string, value: unknown, text: string, column: ?object}} The part, or null when it names no field.
|
|
623
|
+
* @spec openspec/changes/card-layout-part-formatter/specs/card-layout-part-formatter/spec.md#requirement-a-card-meta-part-can-name-its-own-formatter
|
|
624
|
+
*/
|
|
625
|
+
metaPart(part) {
|
|
626
|
+
if (typeof part === 'string' && part !== '') {
|
|
627
|
+
return { field: part, value: readPath(this.object, part), text: this.layoutText(part), column: this.layoutColumn(part) }
|
|
628
|
+
}
|
|
629
|
+
if (!part || typeof part !== 'object' || typeof part.field !== 'string' || part.field === '') {
|
|
630
|
+
return null
|
|
631
|
+
}
|
|
632
|
+
const column = typeof part.formatter === 'string' ? { formatter: part.formatter, formatterOptions: part.formatterOptions } : null
|
|
633
|
+
return { field: part.field, value: readPath(this.object, part.field), text: this.layoutText(part.field, column), column }
|
|
634
|
+
},
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* A field's value as text: a person or a record by its display name,
|
|
638
|
+
* title or name, anything else as a string. '' for an empty value or
|
|
639
|
+
* a field that is not named.
|
|
640
|
+
*
|
|
641
|
+
* @param {unknown} field A dot path into the object.
|
|
642
|
+
* @param {?object} [own] The column to read through instead of the one the field names.
|
|
643
|
+
* @return {string}
|
|
644
|
+
*/
|
|
645
|
+
layoutText(field, own) {
|
|
646
|
+
if (typeof field !== 'string' || field === '') {
|
|
647
|
+
return ''
|
|
648
|
+
}
|
|
649
|
+
const value = readPath(this.object, field)
|
|
650
|
+
if (value === null || value === undefined || value === '') {
|
|
651
|
+
return ''
|
|
652
|
+
}
|
|
653
|
+
// A part whose field names a page column with a formatter reads as
|
|
654
|
+
// its table cell does (a case type uuid as its name).
|
|
655
|
+
const column = own === undefined ? this.layoutColumn(field) : own
|
|
656
|
+
const format = column && column.formatter && this.cnFormatters ? this.cnFormatters[column.formatter] : null
|
|
657
|
+
if (typeof format === 'function') {
|
|
658
|
+
const formatted = format(value, this.object, this.schema?.properties?.[field], column.formatterOptions || undefined)
|
|
659
|
+
return formatted === null || formatted === undefined ? '' : String(formatted)
|
|
660
|
+
}
|
|
661
|
+
if (typeof value === 'object') {
|
|
662
|
+
const name = value.displayName || value.title || value.name
|
|
663
|
+
return typeof name === 'string' ? name : ''
|
|
664
|
+
}
|
|
665
|
+
return String(value)
|
|
666
|
+
},
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* The page column a layout part's field names, or null.
|
|
670
|
+
*
|
|
671
|
+
* @param {string} field The part's field.
|
|
672
|
+
* @return {?object} The column.
|
|
673
|
+
*/
|
|
674
|
+
layoutColumn(field) {
|
|
675
|
+
return (this.cardFieldColumns && typeof field === 'string' && this.cardFieldColumns[field]) || null
|
|
676
|
+
},
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* A pill that reads its date field through the due rules: `variantWhen`
|
|
680
|
+
* (the first rule the days left match gives the tone), else `due`
|
|
681
|
+
* (overdue reads as error, within `due.soonWithin` days as warning).
|
|
682
|
+
* The label is `labels[variant]`, else `labels.overdue` / `labels.soon`,
|
|
683
|
+
* else Overdue / Soon, through the host's translate. Any other date
|
|
684
|
+
* draws no pill.
|
|
685
|
+
*
|
|
686
|
+
* @param {{field: string, due?: object, variantWhen?: Array, labels?: object}} def The pill.
|
|
687
|
+
* @return {?{label: string, variant: string}}
|
|
688
|
+
*/
|
|
689
|
+
datePill(def) {
|
|
690
|
+
const value = readPath(this.object, def.field)
|
|
691
|
+
const variant = Array.isArray(def.variantWhen)
|
|
692
|
+
? this.dateRuleVariant(value, def.variantWhen)
|
|
693
|
+
: this.dueVariant(value, def.due)
|
|
694
|
+
if (variant === '') {
|
|
695
|
+
return null
|
|
696
|
+
}
|
|
697
|
+
const labels = def.labels && typeof def.labels === 'object' ? def.labels : {}
|
|
698
|
+
const state = variant === 'error' ? 'overdue' : (variant === 'warning' ? 'soon' : '')
|
|
699
|
+
const authored = labels[variant] || (state && labels[state])
|
|
700
|
+
if (typeof authored === 'string' && authored !== '') {
|
|
701
|
+
return { label: this.cnTranslate(authored), variant }
|
|
702
|
+
}
|
|
703
|
+
if (state === 'overdue') {
|
|
704
|
+
return { label: t('nextcloud-vue', 'Overdue'), variant }
|
|
705
|
+
}
|
|
706
|
+
if (state === 'soon') {
|
|
707
|
+
return { label: t('nextcloud-vue', 'Soon'), variant }
|
|
708
|
+
}
|
|
709
|
+
return null
|
|
710
|
+
},
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* The variant of the first `variantWhen` rule a date matches, or ''.
|
|
714
|
+
*
|
|
715
|
+
* @param {unknown} value The date.
|
|
716
|
+
* @param {Array} rules The rules.
|
|
717
|
+
* @return {string} The variant, or ''.
|
|
718
|
+
*/
|
|
719
|
+
dateRuleVariant(value, rules) {
|
|
720
|
+
const matched = resolveDateVariant(value, rules)
|
|
721
|
+
return matched === 'default' ? '' : matched
|
|
722
|
+
},
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* The variant the due rules give a date: error when overdue, warning
|
|
726
|
+
* within `soonWithin` days, else ''.
|
|
727
|
+
*
|
|
728
|
+
* @param {unknown} value The date.
|
|
729
|
+
* @param {object} config The `due` config.
|
|
730
|
+
* @return {string} The variant, or ''.
|
|
731
|
+
*/
|
|
732
|
+
dueVariant(value, config) {
|
|
733
|
+
const due = resolveDue(value, config)
|
|
734
|
+
if (due && due.tone === 'danger') {
|
|
735
|
+
return 'error'
|
|
736
|
+
}
|
|
737
|
+
return due && due.soon ? 'warning' : ''
|
|
738
|
+
},
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* A layout pill as `{ label, variant }`, or null while its field is
|
|
742
|
+
* empty.
|
|
743
|
+
*
|
|
744
|
+
* @param {?{field: string, colorMap?: object, labels?: object, variant?: string}} def The pill.
|
|
745
|
+
* @return {?{label: string, variant: string}}
|
|
746
|
+
*/
|
|
747
|
+
layoutPill(def) {
|
|
748
|
+
if (!def || typeof def !== 'object') {
|
|
749
|
+
return null
|
|
750
|
+
}
|
|
751
|
+
if (def.due || Array.isArray(def.variantWhen)) {
|
|
752
|
+
return this.datePill(def)
|
|
753
|
+
}
|
|
754
|
+
const value = this.layoutText(def.field)
|
|
755
|
+
if (value === '') {
|
|
756
|
+
return null
|
|
757
|
+
}
|
|
758
|
+
const labels = def.labels && typeof def.labels === 'object' ? def.labels : {}
|
|
759
|
+
const label = typeof labels[value] === 'string' ? this.cnTranslate(labels[value]) : value
|
|
760
|
+
const colorMap = def.colorMap && typeof def.colorMap === 'object' ? def.colorMap : {}
|
|
761
|
+
const key = Object.keys(colorMap).find((k) => k.toLowerCase() === value.toLowerCase())
|
|
762
|
+
const variant = key !== undefined ? colorMap[key] : def.variant
|
|
763
|
+
return { label, variant: isBadgeVariant(variant) ? variant : 'default' }
|
|
764
|
+
},
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* One fact of the card: the property's value with the matching page
|
|
768
|
+
* column (label, formatter, widget) when there is one.
|
|
769
|
+
*
|
|
770
|
+
* @param {string} key The property key.
|
|
771
|
+
* @param {object} prop The schema property.
|
|
772
|
+
* @return {object} { key, label, value, property, column }
|
|
773
|
+
*/
|
|
774
|
+
metadataField(key, prop) {
|
|
775
|
+
const column = (this.cardFieldColumns && this.cardFieldColumns[key]) || null
|
|
776
|
+
return {
|
|
777
|
+
key,
|
|
778
|
+
label: this.cnTranslate((column && column.label) || prop.title || key),
|
|
779
|
+
value: this.object[key],
|
|
780
|
+
property: prop,
|
|
781
|
+
column,
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
|
|
444
785
|
formatValue,
|
|
445
786
|
|
|
446
787
|
/**
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
:deleteLabel="deleteLabel"
|
|
13
13
|
:uploadButton="uploadButton"
|
|
14
14
|
:dropOverlay="dropOverlay"
|
|
15
|
+
:dropLabel="dropLabel"
|
|
16
|
+
:dropDetail="dropDetail"
|
|
15
17
|
:dropHint="dropHint"
|
|
16
18
|
:rowActions="rowActions"
|
|
17
19
|
:newActions="newActions"
|
|
@@ -347,6 +349,10 @@ export default {
|
|
|
347
349
|
uploadButton: { type: Boolean, default: false },
|
|
348
350
|
/** Forwarded to CnFilesBrowser: the drop state drawn over the list ("Drop to add") and announced. */
|
|
349
351
|
dropOverlay: { type: Boolean, default: false },
|
|
352
|
+
/** Forwarded to CnFilesBrowser: the drop state's line ("Laat los om toe te voegen"); the library's own without it. */
|
|
353
|
+
dropLabel: { type: String, default: undefined },
|
|
354
|
+
/** Forwarded to CnFilesBrowser: the drop state's second line, `{count}` the files dragged; it also makes the overlay fill the panel. */
|
|
355
|
+
dropDetail: { type: String, default: '' },
|
|
350
356
|
/** Forwarded to CnFilesBrowser: "Or drag files onto this list." under the list. */
|
|
351
357
|
dropHint: { type: Boolean, default: false },
|
|
352
358
|
/**
|