@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
|
@@ -164,24 +164,37 @@
|
|
|
164
164
|
@selectObject="onSelectObject" />
|
|
165
165
|
</div>
|
|
166
166
|
</div>
|
|
167
|
-
<
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
167
|
+
<template v-else-if="entry.widget">
|
|
168
|
+
<!-- A single widget with a title of its own heads its panel
|
|
169
|
+
(DqZaakDocumenten); a title the tab already shows is not
|
|
170
|
+
repeated. -->
|
|
171
|
+
<div
|
|
172
|
+
v-if="panelHeading(entry)"
|
|
173
|
+
class="cn-tabs-widget__panel-heading"
|
|
174
|
+
data-testid="cn-tabs-widget-panel-heading">
|
|
175
|
+
<h2 class="cn-tabs-widget__panel-title">
|
|
176
|
+
{{ panelHeading(entry).title }}
|
|
177
|
+
</h2>
|
|
178
|
+
<span v-if="panelHeading(entry).subtitle" class="cn-tabs-widget__panel-subtitle">{{ panelHeading(entry).subtitle }}</span>
|
|
179
|
+
</div>
|
|
180
|
+
<CnDetailWidgetHost
|
|
181
|
+
:widget="entry.widget"
|
|
182
|
+
chrome="bare"
|
|
183
|
+
:availableWidgets="availableWidgets"
|
|
184
|
+
:objectId="objectId"
|
|
185
|
+
:object="objectData"
|
|
186
|
+
:objectType="objectType"
|
|
187
|
+
:schemaObject="schemaObject"
|
|
188
|
+
:register="register"
|
|
189
|
+
:schema="schema"
|
|
190
|
+
:store="store"
|
|
191
|
+
:surface="surface"
|
|
192
|
+
:integrationContext="integrationContext"
|
|
193
|
+
:cnRegistry="cnRegistry"
|
|
194
|
+
@geoSaved="onGeoSaved"
|
|
195
|
+
@openIntegration="onOpenIntegration"
|
|
196
|
+
@selectObject="onSelectObject" />
|
|
197
|
+
</template>
|
|
185
198
|
<CnEmptyContent v-else :name="missingLabel(entry)" />
|
|
186
199
|
</CnTab>
|
|
187
200
|
</CnTabs>
|
|
@@ -361,6 +374,11 @@ export default {
|
|
|
361
374
|
* label written in the manifest reads in the user's language.
|
|
362
375
|
*/
|
|
363
376
|
cnTranslate: { default: () => (key) => key },
|
|
377
|
+
/**
|
|
378
|
+
* CnDetailPage's report of the open body tab, so its side column can
|
|
379
|
+
* follow the tab (a side entry's `tabs`). Null on any other page.
|
|
380
|
+
*/
|
|
381
|
+
cnDetailReportTab: { default: null },
|
|
364
382
|
},
|
|
365
383
|
|
|
366
384
|
props: {
|
|
@@ -804,6 +822,16 @@ export default {
|
|
|
804
822
|
this.activeKey = this.resolvedTabs[index]?.key || ''
|
|
805
823
|
},
|
|
806
824
|
|
|
825
|
+
// Tell the detail page which tab is open (side cards per tab).
|
|
826
|
+
'activeTab.id': {
|
|
827
|
+
immediate: true,
|
|
828
|
+
handler(id) {
|
|
829
|
+
if (typeof this.cnDetailReportTab === 'function') {
|
|
830
|
+
this.cnDetailReportTab(id || '')
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
},
|
|
834
|
+
|
|
807
835
|
// A tab appeared or went. Keep the same tab active; when it is the active
|
|
808
836
|
// tab that went, the first visible one takes over and the hash follows.
|
|
809
837
|
visibleKeys() {
|
|
@@ -996,6 +1024,33 @@ export default {
|
|
|
996
1024
|
return [tab?.widgetId]
|
|
997
1025
|
},
|
|
998
1026
|
|
|
1027
|
+
/**
|
|
1028
|
+
* The title row a single widget's panel draws: the widget's own title
|
|
1029
|
+
* and its description, through the app's translate. None when the
|
|
1030
|
+
* widget has no title or no description, or the tab already shows the
|
|
1031
|
+
* title: a title alone names what the tab already names, so the
|
|
1032
|
+
* widget stays bare in its panel.
|
|
1033
|
+
*
|
|
1034
|
+
* @param {object} entry A resolved tab.
|
|
1035
|
+
* @return {{title: string, subtitle: string}|null} The heading, or null.
|
|
1036
|
+
*/
|
|
1037
|
+
panelHeading(entry) {
|
|
1038
|
+
const widget = entry && entry.widget
|
|
1039
|
+
const raw = widgetTitleOf(widget)
|
|
1040
|
+
if (!raw) {
|
|
1041
|
+
return null
|
|
1042
|
+
}
|
|
1043
|
+
const translate = typeof this.cnTranslate === 'function' ? this.cnTranslate : (key) => key
|
|
1044
|
+
const title = translate(raw)
|
|
1045
|
+
if (title === entry.label) {
|
|
1046
|
+
return null
|
|
1047
|
+
}
|
|
1048
|
+
if (!widget || typeof widget.description !== 'string' || widget.description === '') {
|
|
1049
|
+
return null
|
|
1050
|
+
}
|
|
1051
|
+
return { title, subtitle: translate(widget.description) }
|
|
1052
|
+
},
|
|
1053
|
+
|
|
999
1054
|
/**
|
|
1000
1055
|
* The label a tab shows: the authored `label`, else (board look) History
|
|
1001
1056
|
* for the activity widget, else the child widget's title, else its id.
|
|
@@ -1254,6 +1309,24 @@ export default {
|
|
|
1254
1309
|
|
|
1255
1310
|
<style scoped>
|
|
1256
1311
|
/* A stack (`widgetIds`): the panel's widget, then cards 20px apart. */
|
|
1312
|
+
.cn-tabs-widget__panel-heading {
|
|
1313
|
+
display: flex;
|
|
1314
|
+
flex-direction: column;
|
|
1315
|
+
gap: 4px;
|
|
1316
|
+
margin-bottom: 16px;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
.cn-tabs-widget__panel-title {
|
|
1320
|
+
margin: 0;
|
|
1321
|
+
font-size: 17px;
|
|
1322
|
+
font-weight: 700;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
.cn-tabs-widget__panel-subtitle {
|
|
1326
|
+
font-size: 14px;
|
|
1327
|
+
color: var(--color-text-maxcontrast);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1257
1330
|
.cn-tabs-widget__stack {
|
|
1258
1331
|
display: flex;
|
|
1259
1332
|
flex-direction: column;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
The team today from an app's workload endpoint, with each person's Nextcloud user status.
|
|
2
|
+
|
|
3
|
+
```vue
|
|
4
|
+
<CnTeamWorkloadWidget
|
|
5
|
+
:content="{
|
|
6
|
+
source: { url: '/apps/dossiq/api/work-queue/workload', responsePath: 'handlers', userField: 'handler', countField: 'openCaseCount' },
|
|
7
|
+
capacity: 12,
|
|
8
|
+
}" />
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Props: `content` holds the source, the capacity and the labels.
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
-->
|
|
5
|
+
<template>
|
|
6
|
+
<div class="cn-team-workload" data-testid="cn-team-workload">
|
|
7
|
+
<p v-if="loading && members.length === 0" class="cn-team-workload__state-line" role="status">
|
|
8
|
+
{{ loadingLabel }}
|
|
9
|
+
</p>
|
|
10
|
+
<p v-else-if="members.length === 0" class="cn-team-workload__state-line">
|
|
11
|
+
{{ emptyLabel }}
|
|
12
|
+
</p>
|
|
13
|
+
<ul v-else class="cn-team-workload__list">
|
|
14
|
+
<li
|
|
15
|
+
v-for="member in members"
|
|
16
|
+
:key="member.id"
|
|
17
|
+
class="cn-team-workload__member"
|
|
18
|
+
data-testid="cn-team-workload-member">
|
|
19
|
+
<div class="cn-team-workload__row">
|
|
20
|
+
<span class="cn-team-workload__avatar" aria-hidden="true">{{ member.initials }}</span>
|
|
21
|
+
<span class="cn-team-workload__who">
|
|
22
|
+
<strong class="cn-team-workload__name">{{ member.name }}</strong>
|
|
23
|
+
<span
|
|
24
|
+
class="cn-team-workload__state"
|
|
25
|
+
:class="{ 'cn-team-workload__state--away': !member.available }">{{ member.line }}</span>
|
|
26
|
+
</span>
|
|
27
|
+
<span class="cn-team-workload__count">{{ member.countText }}</span>
|
|
28
|
+
</div>
|
|
29
|
+
<span class="cn-team-workload__bar" aria-hidden="true">
|
|
30
|
+
<span
|
|
31
|
+
class="cn-team-workload__bar-fill"
|
|
32
|
+
:class="{ 'cn-team-workload__bar-fill--hot': member.hot }"
|
|
33
|
+
:style="{ width: member.percent + '%' }" />
|
|
34
|
+
</span>
|
|
35
|
+
</li>
|
|
36
|
+
</ul>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<script>
|
|
41
|
+
import { getCurrentUser } from '@nextcloud/auth'
|
|
42
|
+
import { translatePlural as n, translate as t } from '@nextcloud/l10n'
|
|
43
|
+
import { generateUrl } from '@nextcloud/router'
|
|
44
|
+
import { fetchStatuses } from '../../utils/nextcloudDirectory.js'
|
|
45
|
+
import { readPath } from '../../utils/readPath.js'
|
|
46
|
+
import { userLocale } from '../../utils/userLocale.js'
|
|
47
|
+
|
|
48
|
+
/** The share of the capacity from which a load bar reads as full. */
|
|
49
|
+
const HOT_PERCENT = 90
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* CnTeamWorkloadWidget: the `team-workload` widget ("Team vandaag" on board
|
|
53
|
+
* DqTeamwachtrij). Each person of the team with their initials, name, an
|
|
54
|
+
* availability line, their open count and a load bar; the card's header
|
|
55
|
+
* note says how many are present ("4 of 5 present").
|
|
56
|
+
*
|
|
57
|
+
* The counts come from the app (`content.source`, an endpoint that answers a
|
|
58
|
+
* row per person). The availability comes from Nextcloud's user status, read
|
|
59
|
+
* on the client through the OCS user status API: the person's own message
|
|
60
|
+
* with the time it ends ("In a meeting until 14:00"), else Available, Away or
|
|
61
|
+
* Busy, and Absent today without a status. Present means any status but
|
|
62
|
+
* offline.
|
|
63
|
+
*
|
|
64
|
+
* `content`:
|
|
65
|
+
* - `source`: `{ url, responsePath?, userField?, nameField?, countField? }`;
|
|
66
|
+
* the url goes through `generateUrl`, the rows are read at `responsePath`
|
|
67
|
+
* (else the body), each with the user id at `userField` (default
|
|
68
|
+
* `userId`), the name at `nameField` (default `displayName`) and the count
|
|
69
|
+
* at `countField` (default `count`).
|
|
70
|
+
* - `capacity`: the count at a full bar; without it the highest count is.
|
|
71
|
+
* - `countLabel`: `{ one, other }` with `{count}`, through the app's
|
|
72
|
+
* translate; without it the count reads "{count} open".
|
|
73
|
+
* - `emptyText`: shown without anyone to list.
|
|
74
|
+
*/
|
|
75
|
+
export default {
|
|
76
|
+
name: 'CnTeamWorkloadWidget',
|
|
77
|
+
|
|
78
|
+
inject: {
|
|
79
|
+
cnTranslate: { default: () => (key) => key },
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
props: {
|
|
83
|
+
/** The widget's content: `source`, `capacity`, `countLabel`, `emptyText`. */
|
|
84
|
+
content: {
|
|
85
|
+
type: Object,
|
|
86
|
+
default: () => ({}),
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
emits: ['header'],
|
|
91
|
+
|
|
92
|
+
data() {
|
|
93
|
+
return {
|
|
94
|
+
/** The rows the source answered. */
|
|
95
|
+
rows: [],
|
|
96
|
+
/** The user statuses by user id. */
|
|
97
|
+
statuses: {},
|
|
98
|
+
/** Whether the source is being read. */
|
|
99
|
+
loading: false,
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
computed: {
|
|
104
|
+
/** @return {string} The signed-in user's id. */
|
|
105
|
+
viewerId() {
|
|
106
|
+
return String(getCurrentUser()?.uid || '')
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The people to list, the viewer first and the rest by name, each with
|
|
111
|
+
* the line, count and bar to draw.
|
|
112
|
+
*
|
|
113
|
+
* @return {Array<object>} The members.
|
|
114
|
+
*/
|
|
115
|
+
members() {
|
|
116
|
+
const source = this.content?.source || {}
|
|
117
|
+
const userField = source.userField || 'userId'
|
|
118
|
+
const nameField = source.nameField || 'displayName'
|
|
119
|
+
const countField = source.countField || 'count'
|
|
120
|
+
const people = this.rows
|
|
121
|
+
.filter((row) => row && typeof row === 'object' && readPath(row, userField))
|
|
122
|
+
.map((row) => {
|
|
123
|
+
const id = String(readPath(row, userField))
|
|
124
|
+
const name = String(readPath(row, nameField) || id)
|
|
125
|
+
return { id, name, count: Number(readPath(row, countField)) || 0 }
|
|
126
|
+
})
|
|
127
|
+
const capacity = Number(this.content?.capacity) > 0
|
|
128
|
+
? Number(this.content.capacity)
|
|
129
|
+
: Math.max(1, ...people.map((p) => p.count))
|
|
130
|
+
return people
|
|
131
|
+
.sort((a, b) => (Number(b.id === this.viewerId) - Number(a.id === this.viewerId)) || a.name.localeCompare(b.name))
|
|
132
|
+
.map((person) => {
|
|
133
|
+
const status = this.statuses[person.id] || null
|
|
134
|
+
const percent = Math.min(100, Math.round((person.count / capacity) * 100))
|
|
135
|
+
return {
|
|
136
|
+
...person,
|
|
137
|
+
name: person.id === this.viewerId ? t('nextcloud-vue', '{name} (you)', { name: person.name }) : person.name,
|
|
138
|
+
initials: initialsOf(person.name),
|
|
139
|
+
line: this.lineOf(status),
|
|
140
|
+
available: !!status && status.status === 'online',
|
|
141
|
+
present: isPresent(status),
|
|
142
|
+
countText: this.countText(person.count),
|
|
143
|
+
percent,
|
|
144
|
+
hot: percent >= HOT_PERCENT,
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
/** @return {string} The header note: how many of the team are present. */
|
|
150
|
+
headerNote() {
|
|
151
|
+
const total = this.members.length
|
|
152
|
+
if (total === 0) {
|
|
153
|
+
return ''
|
|
154
|
+
}
|
|
155
|
+
const present = this.members.filter((member) => member.present).length
|
|
156
|
+
return t('nextcloud-vue', '{present} of {total} present', { present, total })
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
/** @return {string} What the card says while it reads. */
|
|
160
|
+
loadingLabel() {
|
|
161
|
+
return t('nextcloud-vue', 'Loading…')
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
/** @return {string} What the card says without anyone to list. */
|
|
165
|
+
emptyLabel() {
|
|
166
|
+
return this.content?.emptyText ? this.cnTranslate(this.content.emptyText) : t('nextcloud-vue', 'No one in the team')
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
watch: {
|
|
171
|
+
headerNote: {
|
|
172
|
+
immediate: true,
|
|
173
|
+
handler(note) {
|
|
174
|
+
/**
|
|
175
|
+
* @event header The card header's parts: `{ link, note, action, pill }`, the note being how many are present.
|
|
176
|
+
*/
|
|
177
|
+
this.$emit('header', { link: null, note, action: null, pill: null })
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
'content.source': {
|
|
182
|
+
deep: true,
|
|
183
|
+
handler() {
|
|
184
|
+
this.load()
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
mounted() {
|
|
190
|
+
this.load()
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
methods: {
|
|
194
|
+
/**
|
|
195
|
+
* Read the counts and the user statuses. A failed read leaves the card
|
|
196
|
+
* empty; a failed status read leaves everyone without a status.
|
|
197
|
+
*
|
|
198
|
+
* @return {Promise<void>}
|
|
199
|
+
*/
|
|
200
|
+
async load() {
|
|
201
|
+
const source = this.content?.source
|
|
202
|
+
if (!source || typeof source.url !== 'string' || source.url === '') {
|
|
203
|
+
this.rows = []
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
this.loading = true
|
|
207
|
+
try {
|
|
208
|
+
const { default: axios } = await import('@nextcloud/axios')
|
|
209
|
+
const [answer, statuses] = await Promise.all([
|
|
210
|
+
axios.get(generateUrl(source.url)),
|
|
211
|
+
fetchStatuses(axios),
|
|
212
|
+
])
|
|
213
|
+
const body = answer && answer.data
|
|
214
|
+
const rows = source.responsePath ? readPath(body, source.responsePath) : body
|
|
215
|
+
this.rows = Array.isArray(rows) ? rows : []
|
|
216
|
+
this.statuses = statuses || {}
|
|
217
|
+
} catch {
|
|
218
|
+
this.rows = []
|
|
219
|
+
} finally {
|
|
220
|
+
this.loading = false
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* The availability line of a user status.
|
|
226
|
+
*
|
|
227
|
+
* @param {object|null} status The user status, or null without one.
|
|
228
|
+
* @return {string} The line.
|
|
229
|
+
*/
|
|
230
|
+
lineOf(status) {
|
|
231
|
+
if (!status) {
|
|
232
|
+
return t('nextcloud-vue', 'Absent today')
|
|
233
|
+
}
|
|
234
|
+
const message = typeof status.message === 'string' ? status.message.trim() : ''
|
|
235
|
+
if (message !== '') {
|
|
236
|
+
const clearAt = Number(status.clearAt)
|
|
237
|
+
if (!Number.isFinite(clearAt) || clearAt <= 0) {
|
|
238
|
+
return message
|
|
239
|
+
}
|
|
240
|
+
const time = new Date(clearAt * 1000).toLocaleTimeString(userLocale() || undefined, { hour: '2-digit', minute: '2-digit' })
|
|
241
|
+
return t('nextcloud-vue', '{message} until {time}', { message, time })
|
|
242
|
+
}
|
|
243
|
+
switch (status.status) {
|
|
244
|
+
case 'online':
|
|
245
|
+
return t('nextcloud-vue', 'Available')
|
|
246
|
+
case 'away':
|
|
247
|
+
return t('nextcloud-vue', 'Away')
|
|
248
|
+
case 'dnd':
|
|
249
|
+
case 'busy':
|
|
250
|
+
return t('nextcloud-vue', 'Busy')
|
|
251
|
+
default:
|
|
252
|
+
return t('nextcloud-vue', 'Absent today')
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* The count as words: the content's `countLabel`, else "{count} open".
|
|
258
|
+
*
|
|
259
|
+
* @param {number} count The open count.
|
|
260
|
+
* @return {string} The text.
|
|
261
|
+
*/
|
|
262
|
+
countText(count) {
|
|
263
|
+
const label = this.content?.countLabel
|
|
264
|
+
if (label && typeof label === 'object' && typeof label.one === 'string' && typeof label.other === 'string') {
|
|
265
|
+
return this.cnTranslate(count === 1 ? label.one : label.other).replace('{count}', String(count))
|
|
266
|
+
}
|
|
267
|
+
return n('nextcloud-vue', '{count} open', '{count} open', count, { count })
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Up to two initials of a name.
|
|
274
|
+
*
|
|
275
|
+
* @param {string} name The name.
|
|
276
|
+
* @return {string} The initials, upper case.
|
|
277
|
+
*/
|
|
278
|
+
function initialsOf(name) {
|
|
279
|
+
const parts = String(name || '').trim().split(/\s+/).filter(Boolean)
|
|
280
|
+
if (parts.length === 0) {
|
|
281
|
+
return ''
|
|
282
|
+
}
|
|
283
|
+
const last = parts.length > 1 ? parts[parts.length - 1].charAt(0) : ''
|
|
284
|
+
return (parts[0].charAt(0) + last).toUpperCase()
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Whether a person is at work today: any status but offline or invisible.
|
|
289
|
+
*
|
|
290
|
+
* @param {object|null} status The user status.
|
|
291
|
+
* @return {boolean} True when present.
|
|
292
|
+
*/
|
|
293
|
+
function isPresent(status) {
|
|
294
|
+
return !!status && status.status !== 'offline' && status.status !== 'invisible'
|
|
295
|
+
}
|
|
296
|
+
</script>
|
|
297
|
+
|
|
298
|
+
<style scoped>
|
|
299
|
+
.cn-team-workload__list {
|
|
300
|
+
display: flex;
|
|
301
|
+
flex-direction: column;
|
|
302
|
+
gap: 14px;
|
|
303
|
+
margin: 0;
|
|
304
|
+
padding: 0;
|
|
305
|
+
list-style: none;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.cn-team-workload__member {
|
|
309
|
+
display: flex;
|
|
310
|
+
flex-direction: column;
|
|
311
|
+
gap: 6px;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.cn-team-workload__row {
|
|
315
|
+
display: flex;
|
|
316
|
+
align-items: center;
|
|
317
|
+
gap: 10px;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.cn-team-workload__avatar {
|
|
321
|
+
display: flex;
|
|
322
|
+
flex: none;
|
|
323
|
+
align-items: center;
|
|
324
|
+
justify-content: center;
|
|
325
|
+
width: 32px;
|
|
326
|
+
height: 32px;
|
|
327
|
+
border-radius: 50%;
|
|
328
|
+
background: var(--color-background-dark);
|
|
329
|
+
color: var(--color-main-text);
|
|
330
|
+
font-size: 12px;
|
|
331
|
+
font-weight: 700;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.cn-team-workload__who {
|
|
335
|
+
display: flex;
|
|
336
|
+
flex: 1;
|
|
337
|
+
flex-direction: column;
|
|
338
|
+
min-width: 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.cn-team-workload__name {
|
|
342
|
+
font-size: 14px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.cn-team-workload__state {
|
|
346
|
+
font-size: 13px;
|
|
347
|
+
color: var(--color-text-maxcontrast);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.cn-team-workload__state--away {
|
|
351
|
+
color: var(--color-warning-text, var(--color-text-maxcontrast));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.cn-team-workload__count {
|
|
355
|
+
font-size: 13px;
|
|
356
|
+
font-weight: 600;
|
|
357
|
+
white-space: nowrap;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.cn-team-workload__bar {
|
|
361
|
+
display: block;
|
|
362
|
+
height: 6px;
|
|
363
|
+
overflow: hidden;
|
|
364
|
+
border-radius: 3px;
|
|
365
|
+
background: var(--color-border);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.cn-team-workload__bar-fill {
|
|
369
|
+
display: block;
|
|
370
|
+
height: 100%;
|
|
371
|
+
background: var(--color-primary-element);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.cn-team-workload__bar-fill--hot {
|
|
375
|
+
background: var(--color-error);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.cn-team-workload__state-line {
|
|
379
|
+
margin: 0;
|
|
380
|
+
color: var(--color-text-maxcontrast);
|
|
381
|
+
}
|
|
382
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* CnTeamWorkloadWidget: the `team-workload` widget (the team today, with
|
|
6
|
+
* each person's availability and open count). It is registered in
|
|
7
|
+
* `CnWidgetGrid/registerDashboardWidgets.js`, inline, because a bare
|
|
8
|
+
* side-effect import of this module may be tree-shaken away.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import CnTeamWorkloadWidget from './CnTeamWorkloadWidget.vue'
|
|
12
|
+
|
|
13
|
+
export { CnTeamWorkloadWidget }
|
|
14
|
+
export default CnTeamWorkloadWidget
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
<div class="cn-version-info__details">
|
|
36
36
|
<!-- Application Name (the board card can leave it to its description: `showAppName`) -->
|
|
37
37
|
<div v-if="!isBoard || (showAppName && !compact)" class="cn-version-info__item" data-testid="cn-version-info-app-name">
|
|
38
|
-
<span class="cn-version-info__label">{{ fieldLabels.appName }}
|
|
38
|
+
<span class="cn-version-info__label">{{ fieldLabels.appName }}{{ labelColon }}</span>
|
|
39
39
|
<span class="cn-version-info__value">{{ appName }}</span>
|
|
40
40
|
</div>
|
|
41
41
|
|
|
42
42
|
<!-- Version -->
|
|
43
43
|
<div class="cn-version-info__item">
|
|
44
|
-
<span class="cn-version-info__label">{{ fieldLabels.version }}
|
|
44
|
+
<span class="cn-version-info__label">{{ fieldLabels.version }}{{ labelColon }}</span>
|
|
45
45
|
<span class="cn-version-info__value">{{ appVersion }}</span>
|
|
46
46
|
</div>
|
|
47
47
|
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
which draws the row ("Unknown" until the app reports it) with the
|
|
50
50
|
up-to-date state inline ("0.4.47, bijgewerkt"). -->
|
|
51
51
|
<div v-if="configuredVersion || isBoard" class="cn-version-info__item" data-testid="cn-version-info-configured">
|
|
52
|
-
<span class="cn-version-info__label">{{ fieldLabels.configuredVersion }}
|
|
52
|
+
<span class="cn-version-info__label">{{ fieldLabels.configuredVersion }}{{ labelColon }}</span>
|
|
53
53
|
<span class="cn-version-info__value">{{ isBoard ? boardConfiguredText : configuredVersion }}</span>
|
|
54
54
|
</div>
|
|
55
55
|
|
|
56
56
|
<!-- Additional items -->
|
|
57
57
|
<div v-for="item in additionalItems" :key="item.label" class="cn-version-info__item">
|
|
58
|
-
<span class="cn-version-info__label">{{ item.label }}
|
|
58
|
+
<span class="cn-version-info__label">{{ item.label }}{{ labelColon }}</span>
|
|
59
59
|
<span class="cn-version-info__value" :class="item.statusClass">{{ item.value }}</span>
|
|
60
60
|
</div>
|
|
61
61
|
|
|
@@ -320,6 +320,17 @@ export default {
|
|
|
320
320
|
},
|
|
321
321
|
|
|
322
322
|
computed: {
|
|
323
|
+
/**
|
|
324
|
+
* The colon after each label: none on the compact board card, which
|
|
325
|
+
* sets each label beside its value ("Versie 0.4.47", DqInstellingenAlgemeen);
|
|
326
|
+
* one otherwise, PqBeheer's card included.
|
|
327
|
+
*
|
|
328
|
+
* @return {string} The colon, or ''.
|
|
329
|
+
*/
|
|
330
|
+
labelColon() {
|
|
331
|
+
return this.isBoard && this.compact ? '' : ':'
|
|
332
|
+
},
|
|
333
|
+
|
|
323
334
|
/**
|
|
324
335
|
* The field labels: the app's, else the library's in the reader's language.
|
|
325
336
|
*
|
|
@@ -21,6 +21,7 @@ import CnExportsWidget from '../CnExportsWidget/CnExportsWidget.vue'
|
|
|
21
21
|
import CnHeaderWidget from '../CnHeaderWidget/CnHeaderWidget.vue'
|
|
22
22
|
import CnIntegrationWidget from '../CnIntegrationWidget/CnIntegrationWidget.vue'
|
|
23
23
|
import CnNavCardGrid from '../CnNavCardGrid/CnNavCardGrid.vue'
|
|
24
|
+
import CnNoticeWidget from '../CnNoticeWidget/CnNoticeWidget.vue'
|
|
24
25
|
import CnObjectDataWidget from '../CnObjectDataWidget/CnObjectDataWidget.vue'
|
|
25
26
|
import CnObjectGeoWidget from '../CnObjectGeoWidget/CnObjectGeoWidget.vue'
|
|
26
27
|
import CnObjectMetadataWidget from '../CnObjectMetadataWidget/CnObjectMetadataWidget.vue'
|
|
@@ -86,6 +87,7 @@ export const BUILT_IN_WIDGETS = {
|
|
|
86
87
|
related: CnRelatedObjectsWidget,
|
|
87
88
|
integration: CnIntegrationWidget,
|
|
88
89
|
banner: CnBannerWidget,
|
|
90
|
+
notice: CnNoticeWidget,
|
|
89
91
|
'audit-trail': CnAuditTrailWidget,
|
|
90
92
|
timeline: CnTimelineWidget,
|
|
91
93
|
header: CnHeaderWidget,
|
|
@@ -40,6 +40,7 @@ import CnStatsBlockWidget from '../CnStatsBlockWidget/CnStatsBlockWidget.vue'
|
|
|
40
40
|
import CnStatsBlockWidgetForm from '../CnStatsBlockWidgetForm/CnStatsBlockWidgetForm.vue'
|
|
41
41
|
import CnTabsWidget from '../CnTabsWidget/CnTabsWidget.vue'
|
|
42
42
|
import CnTabsWidgetForm from '../CnTabsWidgetForm/CnTabsWidgetForm.vue'
|
|
43
|
+
import CnTeamWorkloadWidget from '../CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue'
|
|
43
44
|
import CnWeekStripWidget from '../CnWeekStripWidget/CnWeekStripWidget.vue'
|
|
44
45
|
import CnWeekStripWidgetForm from '../CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue'
|
|
45
46
|
// Typed widgets registered with an explicit renderer + config FORM. chart /
|
|
@@ -381,6 +382,17 @@ registerDashboardWidget('stacked-bar', {
|
|
|
381
382
|
icon: 'ChartBar',
|
|
382
383
|
})
|
|
383
384
|
|
|
385
|
+
// The team today: availability from the Nextcloud user status and each
|
|
386
|
+
// person's open count from the app (DqTeamwachtrij "Team vandaag"). Placed
|
|
387
|
+
// from the manifest: there is no config form yet.
|
|
388
|
+
registerDashboardWidget('team-workload', {
|
|
389
|
+
renderer: CnTeamWorkloadWidget,
|
|
390
|
+
form: null,
|
|
391
|
+
defaultContent: { source: { url: '', responsePath: '', userField: 'userId', nameField: 'displayName', countField: 'count' } },
|
|
392
|
+
displayName: 'Team workload',
|
|
393
|
+
icon: 'AccountGroup',
|
|
394
|
+
})
|
|
395
|
+
|
|
384
396
|
/**
|
|
385
397
|
* Explicit no-op that guarantees this module (and therefore every widget's
|
|
386
398
|
* self-registration side effect) is evaluated. Now optional: `CnDashboardPage`
|
package/src/components/index.js
CHANGED
|
@@ -131,6 +131,7 @@ export { CnContactPicker } from './CnContactPicker/index.js'
|
|
|
131
131
|
export { CnContactCreate } from './CnContactCreate/index.js'
|
|
132
132
|
export { CnResourceSelect } from './CnResourceSelect/index.js'
|
|
133
133
|
export { CnSearchSelect } from './CnSearchSelect/index.js'
|
|
134
|
+
export { CnNoticeWidget } from './CnNoticeWidget/index.js'
|
|
134
135
|
export { CnPropertySourceField } from './CnPropertySourceField/index.js'
|
|
135
136
|
export { CnDurationField } from './CnDurationField/index.js'
|
|
136
137
|
export { CnFavouriteToggle } from './CnFavouriteToggle/index.js'
|
|
@@ -425,6 +426,7 @@ export { CnGuardianHome } from './CnGuardianHome/index.js'
|
|
|
425
426
|
export { CnWeekStripWidget } from './CnWeekStripWidget/index.js'
|
|
426
427
|
export { CnWeekStripWidgetForm } from './CnWeekStripWidgetForm/index.js'
|
|
427
428
|
export { CnStackedBarWidget } from './CnStackedBarWidget/index.js'
|
|
429
|
+
export { CnTeamWorkloadWidget } from './CnTeamWorkloadWidget/index.js'
|
|
428
430
|
export { CnStackedBarWidgetForm } from './CnStackedBarWidgetForm/index.js'
|
|
429
431
|
export { CnSegmentedControl } from './CnSegmentedControl/index.js'
|
|
430
432
|
export { CnBrandStripe } from './CnBrandStripe/index.js'
|