@conduction/nextcloud-vue 2.83.0 → 2.85.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 +131 -3
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +54 -18
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +232 -4
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +95 -51
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue.js +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue2.js +22 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue2.js.map +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue3.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +47 -4
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue.js +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +239 -3
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +5 -5
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +50 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +22 -12
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue.js +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue2.js +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +226 -8
- 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/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +3 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- 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 +18 -5
- 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/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +38 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +45 -5
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue.js +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue2.js +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +548 -77
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +191 -82
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +11 -2
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js +29 -6
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +126 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +24 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +106 -3
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +67 -5
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js +181 -124
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue.js +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js +135 -2
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +95 -43
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue.js +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js +5 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue.js +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +72 -5
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +33 -8
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +135 -11
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -2
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +17 -2
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +39 -6
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +140 -7
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +37 -9
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +6 -5
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue.js +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +16 -0
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +2 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js +53 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js +3 -2
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +135 -0
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +19 -0
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +37 -19
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/composables/useListView.js +21 -0
- package/dist/esm/composables/useListView.js.map +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue.js +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js +68 -6
- package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js.map +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js +133 -105
- package/dist/esm/dialogs/CnTransitionInputDialog.vue3.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 +38 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +78 -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 +1030 -533
- package/dist/esm/store/useObjectStore.js +16 -2
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/boardColumns.js +8 -1
- package/dist/esm/utils/boardColumns.js.map +1 -1
- package/dist/esm/utils/boardReferenceColumns.js +278 -0
- package/dist/esm/utils/boardReferenceColumns.js.map +1 -0
- package/dist/esm/utils/buildManifest.js +41 -4
- package/dist/esm/utils/buildManifest.js.map +1 -1
- package/dist/esm/utils/detailWidgetVisibility.js +149 -0
- package/dist/esm/utils/detailWidgetVisibility.js.map +1 -0
- package/dist/esm/utils/formatMetric.js +39 -3
- package/dist/esm/utils/formatMetric.js.map +1 -1
- package/dist/esm/utils/gridStack.js +40 -1
- package/dist/esm/utils/gridStack.js.map +1 -1
- package/dist/esm/utils/humaniseKey.js +41 -0
- package/dist/esm/utils/humaniseKey.js.map +1 -0
- package/dist/esm/utils/notificationRuleLabel.js +6 -23
- package/dist/esm/utils/notificationRuleLabel.js.map +1 -1
- package/dist/esm/utils/resolveManifestTokens.js +1 -0
- package/dist/esm/utils/resolveManifestTokens.js.map +1 -1
- package/dist/esm/utils/sentinelTokens.js +9 -0
- package/dist/esm/utils/sentinelTokens.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/widgetDispatch.js +8 -2
- package/dist/esm/utils/widgetDispatch.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +17159 -13422
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1030 -533
- package/l10n/en.json +38 -1
- package/l10n/nl.json +78 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +160 -8
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +1 -1
- package/src/components/CnBoardView/CnBoardView.vue +262 -6
- package/src/components/CnBodySections/CnBodySections.vue +22 -1
- package/src/components/CnCountdownWidget/CnCountdownWidget.vue +47 -4
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +244 -8
- package/src/components/CnDashboardPage/CnDashboardPage.vue +62 -2
- package/src/components/CnDeltaWidget/CnDeltaWidget.vue +1 -1
- package/src/components/CnDetailPage/CnDetailPage.md +3 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +226 -8
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +3 -1
- package/src/components/CnFactsWidget/CnFactsWidget.vue +18 -5
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +63 -1
- package/src/components/CnGaugeWidget/CnGaugeWidget.vue +1 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +586 -25
- package/src/components/CnIndexPage/useSelfFetchList.js +10 -1
- package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +29 -6
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +154 -5
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +106 -3
- package/src/components/CnRegisterMapping/CnRegisterMapping.md +5 -0
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +231 -96
- package/src/components/CnReportsPage/CnReportsPage.vue +179 -1
- package/src/components/CnSettingsPage/CnSettingsPage.vue +5 -1
- package/src/components/CnStagesWidget/CnStagesWidget.vue +103 -6
- package/src/components/CnStatWidget/CnStatWidget.vue +137 -12
- package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +34 -3
- package/src/components/CnTabsWidget/CnTabsWidget.vue +39 -6
- package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +140 -7
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.md +2 -1
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +42 -13
- package/src/components/CnWalkthrough/CnWalkthrough.vue +16 -0
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +2 -1
- package/src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue +55 -2
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +135 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +10 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +44 -1
- package/src/composables/useListView.js +21 -0
- package/src/css/board.css +65 -4
- package/src/css/dialog.css +4 -2
- package/src/css/form-field.css +14 -0
- package/src/css/form-widget.css +11 -0
- package/src/css/index-page.css +49 -0
- package/src/css/kpi-card.css +13 -0
- package/src/css/look-board-reports.css +58 -0
- package/src/css/look-board.css +108 -7
- package/src/dialogs/CnTransitionInputDialog.vue +87 -7
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +137 -6
- package/src/store/useObjectStore.js +16 -2
- package/src/utils/boardColumns.js +8 -1
- package/src/utils/boardReferenceColumns.js +274 -0
- package/src/utils/buildManifest.js +40 -3
- package/src/utils/detailWidgetVisibility.js +145 -0
- package/src/utils/formatMetric.js +38 -2
- package/src/utils/gridStack.js +39 -0
- package/src/utils/humaniseKey.js +38 -0
- package/src/utils/notificationRuleLabel.js +5 -23
- package/src/utils/resolveManifestTokens.js +1 -0
- package/src/utils/sentinelTokens.js +9 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/widgetDispatch.js +8 -2
|
@@ -87,9 +87,10 @@ With `title`, `description`, `docUrl`, `cardTitle`, `loading`, and `labels`:
|
|
|
87
87
|
| `title` | String | `'Version information'` | Section heading (passed to the wrapping CnSettingsSection) |
|
|
88
88
|
| `description` | String | `'Information about the current application installation'` | Section sub-heading |
|
|
89
89
|
| `docUrl` | String | `''` | Documentation URL — shows an info icon link next to the section title |
|
|
90
|
+
| `wide` | Boolean | `true` | Under the board look the card spans the whole settings grid, as the boards draw it. `false` keeps it one card in the grid. No effect without the board look. |
|
|
90
91
|
| `cardTitle` | String | `'Application information'` | Heading inside the gray version card |
|
|
91
92
|
| `loading` | Boolean | `false` | Show a loading spinner and hide the card content while data is fetching |
|
|
92
|
-
| `labels` | Object | `{
|
|
93
|
+
| `labels` | Object | `{}` | Custom labels for the standard row headings (`appName`, `version`, `configuredVersion`); a label left out keeps the translated default |
|
|
93
94
|
|
|
94
95
|
|
|
95
96
|
`look` is documented in the prop table of the component reference (board look, screens-chrome-parity).
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
:description="description"
|
|
5
5
|
:docUrl="docUrl"
|
|
6
6
|
:loading="loading"
|
|
7
|
-
|
|
7
|
+
:wide="isBoard && wide"
|
|
8
|
+
:loadingMessage="t('nextcloud-vue', 'Loading version information…')">
|
|
8
9
|
<!-- Actions slot (top right). Under the board look the same buttons sit
|
|
9
10
|
in the footer row of the card instead. -->
|
|
10
11
|
<template v-if="!isBoard" #actions>
|
|
@@ -34,19 +35,19 @@
|
|
|
34
35
|
<div class="cn-version-info__details">
|
|
35
36
|
<!-- Application Name -->
|
|
36
37
|
<div class="cn-version-info__item">
|
|
37
|
-
<span class="cn-version-info__label">{{
|
|
38
|
+
<span class="cn-version-info__label">{{ fieldLabels.appName }}:</span>
|
|
38
39
|
<span class="cn-version-info__value">{{ appName }}</span>
|
|
39
40
|
</div>
|
|
40
41
|
|
|
41
42
|
<!-- Version -->
|
|
42
43
|
<div class="cn-version-info__item">
|
|
43
|
-
<span class="cn-version-info__label">{{
|
|
44
|
+
<span class="cn-version-info__label">{{ fieldLabels.version }}:</span>
|
|
44
45
|
<span class="cn-version-info__value">{{ appVersion }}</span>
|
|
45
46
|
</div>
|
|
46
47
|
|
|
47
48
|
<!-- Configured Version (if provided) -->
|
|
48
49
|
<div v-if="configuredVersion" class="cn-version-info__item">
|
|
49
|
-
<span class="cn-version-info__label">{{
|
|
50
|
+
<span class="cn-version-info__label">{{ fieldLabels.configuredVersion }}:</span>
|
|
50
51
|
<span class="cn-version-info__value">{{ configuredVersion }}</span>
|
|
51
52
|
</div>
|
|
52
53
|
|
|
@@ -157,6 +158,18 @@ export default {
|
|
|
157
158
|
default: '',
|
|
158
159
|
},
|
|
159
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Under the board look the card spans the whole settings grid, as the
|
|
163
|
+
* boards draw the version card. Set to `false` to keep it one card in
|
|
164
|
+
* the grid. Without the board look it has no effect.
|
|
165
|
+
*
|
|
166
|
+
* @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid
|
|
167
|
+
*/
|
|
168
|
+
wide: {
|
|
169
|
+
type: Boolean,
|
|
170
|
+
default: true,
|
|
171
|
+
},
|
|
172
|
+
|
|
160
173
|
/** Section title */
|
|
161
174
|
title: {
|
|
162
175
|
type: String,
|
|
@@ -232,14 +245,13 @@ export default {
|
|
|
232
245
|
default: false,
|
|
233
246
|
},
|
|
234
247
|
|
|
235
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* Custom labels for the standard fields, `{ appName?, version?, configuredVersion? }`.
|
|
250
|
+
* A label left out keeps the translated default.
|
|
251
|
+
*/
|
|
236
252
|
labels: {
|
|
237
253
|
type: Object,
|
|
238
|
-
default: () => ({
|
|
239
|
-
appName: 'Application Name',
|
|
240
|
-
version: 'Version',
|
|
241
|
-
configuredVersion: 'Configured Version',
|
|
242
|
-
}),
|
|
254
|
+
default: () => ({}),
|
|
243
255
|
},
|
|
244
256
|
},
|
|
245
257
|
|
|
@@ -251,6 +263,21 @@ export default {
|
|
|
251
263
|
},
|
|
252
264
|
|
|
253
265
|
computed: {
|
|
266
|
+
/**
|
|
267
|
+
* The field labels: the app's, else the library's in the reader's language.
|
|
268
|
+
*
|
|
269
|
+
* @return {{appName: string, version: string, configuredVersion: string}}
|
|
270
|
+
* @spec openspec/changes/version-card-dutch-and-header/specs/settings-board-look/spec.md#requirement-the-admin-chrome-reads-in-the-readers-language
|
|
271
|
+
*/
|
|
272
|
+
fieldLabels() {
|
|
273
|
+
return {
|
|
274
|
+
appName: t('nextcloud-vue', 'Application name'),
|
|
275
|
+
version: t('nextcloud-vue', 'Version'),
|
|
276
|
+
configuredVersion: t('nextcloud-vue', 'Configured version'),
|
|
277
|
+
...(this.labels || {}),
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
|
|
254
281
|
/** @return {string} Button type based on update status */
|
|
255
282
|
updateButtonType() {
|
|
256
283
|
if (this.isUpToDate) {
|
|
@@ -267,16 +294,18 @@ export default {
|
|
|
267
294
|
/** @return {string} Update button label text */
|
|
268
295
|
updateButtonText() {
|
|
269
296
|
if (this.updating) {
|
|
270
|
-
return 'Updating
|
|
297
|
+
return t('nextcloud-vue', 'Updating…')
|
|
271
298
|
}
|
|
272
299
|
if (this.isUpToDate) {
|
|
273
|
-
return 'Up to date'
|
|
300
|
+
return t('nextcloud-vue', 'Up to date')
|
|
274
301
|
}
|
|
275
|
-
return 'Update'
|
|
302
|
+
return t('nextcloud-vue', 'Update')
|
|
276
303
|
},
|
|
277
304
|
},
|
|
278
305
|
|
|
279
306
|
methods: {
|
|
307
|
+
t,
|
|
308
|
+
|
|
280
309
|
handleUpdateClick() {
|
|
281
310
|
if (!this.updateButtonDisabled) {
|
|
282
311
|
this.$emit('update')
|
|
@@ -683,11 +683,27 @@ export default {
|
|
|
683
683
|
* deferred tour) go through here — so a centered step cannot be
|
|
684
684
|
* swallowed by either.
|
|
685
685
|
*
|
|
686
|
+
* A tour that declares `startOn` opens only on one of those route
|
|
687
|
+
* names, whatever its first step looks like.
|
|
688
|
+
*
|
|
686
689
|
* @param {object} tour The tour definition.
|
|
687
690
|
* @param {string} [routeName] The current route name.
|
|
688
691
|
* @return {boolean} True when the tour may open on this route.
|
|
692
|
+
* @spec openspec/changes/a-tour-starts-on-the-pages-it-names/specs/walkthrough/spec.md
|
|
689
693
|
*/
|
|
690
694
|
routeMatchesTour(tour, routeName) {
|
|
695
|
+
// A tour that names where it starts (`startOn`) opens only there.
|
|
696
|
+
// It wins over the centered-step rule below: a welcome card floats
|
|
697
|
+
// in the middle of the screen, but a user who opens a case from a
|
|
698
|
+
// mail link lands on that case, and the card then blocks the page
|
|
699
|
+
// they came for. Measured 13 October on dossiq: a staff user's first
|
|
700
|
+
// visit was a deep link to a Woo request, and "Welcome to Dossiq"
|
|
701
|
+
// opened over it. The tour waits in `_pendingAutoTour` and opens when
|
|
702
|
+
// the user reaches a named route.
|
|
703
|
+
const startOn = Array.isArray(tour && tour.startOn) ? tour.startOn.map(String) : []
|
|
704
|
+
if (startOn.length > 0) {
|
|
705
|
+
return !!routeName && startOn.includes(String(routeName))
|
|
706
|
+
}
|
|
691
707
|
const page = this.firstStepPage(tour)
|
|
692
708
|
if (!page) {
|
|
693
709
|
return true
|
|
@@ -89,7 +89,8 @@ const DEFAULT_LIMIT = 100
|
|
|
89
89
|
*
|
|
90
90
|
* It renders the five working days by default (`days: 7` adds the weekend),
|
|
91
91
|
* highlights today, marks items that are late, and says so when a day has
|
|
92
|
-
* nothing. On a narrow screen the strip scrolls sideways
|
|
92
|
+
* nothing. On a narrow screen the strip scrolls sideways; under the board
|
|
93
|
+
* look (`.cn-look-board`) the days wrap into rows instead.
|
|
93
94
|
*
|
|
94
95
|
* Items come from an OpenRegister source (one request for the whole week) or
|
|
95
96
|
* from static `items`. Resolved by its registry type key `week-strip`.
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
:title="title"
|
|
15
15
|
:widgetId="widgetId"
|
|
16
16
|
:documentationUrl="documentationUrl"
|
|
17
|
+
:refreshing="epLoading"
|
|
17
18
|
flush>
|
|
18
19
|
<div class="cn-widget-card-grid">
|
|
19
20
|
<CnObjectCard
|
|
20
|
-
v-for="(item, index) in
|
|
21
|
+
v-for="(item, index) in cards"
|
|
21
22
|
:key="item.id || index"
|
|
22
23
|
:object="item" />
|
|
23
24
|
</div>
|
|
@@ -26,7 +27,10 @@
|
|
|
26
27
|
|
|
27
28
|
<script>
|
|
28
29
|
import { translate as t } from '@nextcloud/l10n'
|
|
30
|
+
import { inject, ref } from 'vue'
|
|
29
31
|
import CnObjectCard from '../CnObjectCard/CnObjectCard.vue'
|
|
32
|
+
import { useEndpointSource } from '../../composables/useEndpointSource.js'
|
|
33
|
+
import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'
|
|
30
34
|
import { CnWidgetWrapper } from '../CnWidgetWrapper/index.js'
|
|
31
35
|
|
|
32
36
|
/**
|
|
@@ -35,7 +39,9 @@ import { CnWidgetWrapper } from '../CnWidgetWrapper/index.js'
|
|
|
35
39
|
* Renders the card grid on the shared CnWidgetWrapper chrome, which supplies
|
|
36
40
|
* the widget title and the standard overflow Actions menu (Refresh /
|
|
37
41
|
* Documentation / Request a feature). Each entry in `objects` is rendered as a
|
|
38
|
-
* CnObjectCard.
|
|
42
|
+
* CnObjectCard. Without `objects`, an `endpointSource` (`{ url, method?,
|
|
43
|
+
* params?, responsePath? }`, as on the object table) supplies them: the
|
|
44
|
+
* payload after `responsePath` is the array of objects.
|
|
39
45
|
*/
|
|
40
46
|
export default {
|
|
41
47
|
name: 'CnWidgetCardGrid',
|
|
@@ -75,6 +81,53 @@ export default {
|
|
|
75
81
|
type: Array,
|
|
76
82
|
default: () => [],
|
|
77
83
|
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Read the objects from an app endpoint: `{ url, method?, params?,
|
|
87
|
+
* responsePath? }`, with the token grammar of widget filters. Ignored
|
|
88
|
+
* while `objects` holds any.
|
|
89
|
+
*
|
|
90
|
+
* @type {object|null}
|
|
91
|
+
*/
|
|
92
|
+
endpointSource: {
|
|
93
|
+
type: Object,
|
|
94
|
+
default: null,
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
setup(props) {
|
|
99
|
+
const objectCtxRaw = inject('cnObjectContext', null)
|
|
100
|
+
const detailCtxRaw = inject('cnDetailObjectContext', null)
|
|
101
|
+
const workspaceRaw = inject('cnWorkspaceContext', ref(null))
|
|
102
|
+
const appConfigRaw = inject('cnAppConfig', ref({}))
|
|
103
|
+
const unwrap = (v) => ((v && typeof v === 'object' && 'value' in v) ? v.value : v)
|
|
104
|
+
const { data, loading } = useEndpointSource(
|
|
105
|
+
() => ((props.objects && props.objects.length > 0) ? null : props.endpointSource),
|
|
106
|
+
{
|
|
107
|
+
ctx: () => ({
|
|
108
|
+
...(resolveObjectTokenContext(objectCtxRaw, detailCtxRaw) || {}),
|
|
109
|
+
workspace: unwrap(workspaceRaw) || {},
|
|
110
|
+
config: unwrap(appConfigRaw) || {},
|
|
111
|
+
}),
|
|
112
|
+
widgetId: () => props.widgetId,
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
return { epData: data, epLoading: loading }
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
computed: {
|
|
119
|
+
/**
|
|
120
|
+
* The objects drawn: `objects` when given, else the endpoint's array.
|
|
121
|
+
*
|
|
122
|
+
* @return {Array<object>}
|
|
123
|
+
* @spec openspec/changes/endpoint-source-card-grid-record-list/specs/dashboard-page/spec.md#requirement-a-record-list-and-a-card-grid-can-read-an-endpoint
|
|
124
|
+
*/
|
|
125
|
+
cards() {
|
|
126
|
+
if (this.objects && this.objects.length > 0) {
|
|
127
|
+
return this.objects
|
|
128
|
+
}
|
|
129
|
+
return Array.isArray(this.epData) ? this.epData : []
|
|
130
|
+
},
|
|
78
131
|
},
|
|
79
132
|
}
|
|
80
133
|
</script>
|
|
@@ -88,6 +88,7 @@ import { dispatchAction, resolveObjectOpType } from '../../utils/actionsDispatch
|
|
|
88
88
|
import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'
|
|
89
89
|
import { pageFilter, pageSort } from '../../utils/pageControls.js'
|
|
90
90
|
import { dropOptionalUnresolved, hasUnresolvedTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
|
|
91
|
+
import { fieldsFromSchema } from '../../utils/schema.js'
|
|
91
92
|
import { compareVisibleWhen, readVisibleWhenPath } from '../../utils/visibleWhen.js'
|
|
92
93
|
import { CnIcon } from '../CnIcon/index.js'
|
|
93
94
|
import { CnRowActions } from '../CnRowActions/index.js'
|
|
@@ -231,6 +232,12 @@ export default {
|
|
|
231
232
|
* the object form (`{ key, label, sortable, width, cellClass,
|
|
232
233
|
* formatter, widget, format, aggregate }`) both pass straight through.
|
|
233
234
|
*
|
|
235
|
+
* A column that holds a reference shows the referenced object's label
|
|
236
|
+
* with `labelField` (the property to show) and/or `resolve`
|
|
237
|
+
* (`{ register, schema, labelField? }`, where the reference points).
|
|
238
|
+
* Without `resolve` the target is read off the source schema's `$ref`
|
|
239
|
+
* for that property. Such a column renders as an `fkResolve` cell.
|
|
240
|
+
*
|
|
234
241
|
* @type {Array<object|string>}
|
|
235
242
|
*/
|
|
236
243
|
columns: {
|
|
@@ -469,6 +476,8 @@ export default {
|
|
|
469
476
|
confirmAction: null,
|
|
470
477
|
/** @type {object|null} The row the pending confirm-gated action targets. */
|
|
471
478
|
confirmRow: null,
|
|
479
|
+
/** Where each label column's references point, read off the source schema, by column key. */
|
|
480
|
+
refTargets: {},
|
|
472
481
|
}
|
|
473
482
|
},
|
|
474
483
|
|
|
@@ -638,6 +647,57 @@ export default {
|
|
|
638
647
|
return params
|
|
639
648
|
},
|
|
640
649
|
|
|
650
|
+
/**
|
|
651
|
+
* Columns that ask for the label of the object they reference
|
|
652
|
+
* (`labelField` or `resolve`) and draw no cell widget of their own.
|
|
653
|
+
*
|
|
654
|
+
* @return {Array<object>}
|
|
655
|
+
* @spec openspec/changes/dashboard-table-reference-labels/specs/dashboard-page/spec.md#requirement-a-dashboard-table-shows-a-referenced-objects-label
|
|
656
|
+
*/
|
|
657
|
+
refLabelColumns() {
|
|
658
|
+
return (this.columns || []).filter((col) => col && typeof col === 'object' && !col.widget
|
|
659
|
+
&& ((typeof col.labelField === 'string' && col.labelField !== '') || (col.resolve && typeof col.resolve === 'object')))
|
|
660
|
+
},
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* The columns handed to CnDataTable: a label column whose target is
|
|
664
|
+
* known renders as an `fkResolve` cell; every other column as given.
|
|
665
|
+
*
|
|
666
|
+
* @return {Array<object|string>}
|
|
667
|
+
* @spec openspec/changes/dashboard-table-reference-labels/specs/dashboard-page/spec.md#requirement-a-dashboard-table-shows-a-referenced-objects-label
|
|
668
|
+
*/
|
|
669
|
+
renderedColumns() {
|
|
670
|
+
if (this.refLabelColumns.length === 0) {
|
|
671
|
+
return this.columns
|
|
672
|
+
}
|
|
673
|
+
return this.columns.map((col) => {
|
|
674
|
+
if (!this.refLabelColumns.includes(col)) {
|
|
675
|
+
return col
|
|
676
|
+
}
|
|
677
|
+
const target = this.refTargetOf(col)
|
|
678
|
+
if (!target) {
|
|
679
|
+
return col
|
|
680
|
+
}
|
|
681
|
+
const labelField = (col.resolve && typeof col.resolve.labelField === 'string' && col.resolve.labelField) || col.labelField || 'name'
|
|
682
|
+
return { ...col, widget: 'fkResolve', widgetProps: { ...(col.widgetProps || {}), register: target.register, schema: target.schema, labelField } }
|
|
683
|
+
})
|
|
684
|
+
},
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* The label columns whose target has to be read off the source schema.
|
|
688
|
+
*
|
|
689
|
+
* @return {string[]} Their keys.
|
|
690
|
+
*/
|
|
691
|
+
schemaRefKeys() {
|
|
692
|
+
return this.refLabelColumns.filter((col) => !this.explicitTarget(col)).map((col) => col.key)
|
|
693
|
+
},
|
|
694
|
+
|
|
695
|
+
/** @return {string} The label columns to look up and the source schema, to read again when either changes. */
|
|
696
|
+
refTargetsKey() {
|
|
697
|
+
const src = this.source || {}
|
|
698
|
+
return `${src.register || ''}/${src.schema || ''}:${this.schemaRefKeys.join('|')}`
|
|
699
|
+
},
|
|
700
|
+
|
|
641
701
|
/**
|
|
642
702
|
* `$props` minus the chrome props (`title`, `documentationUrl`,
|
|
643
703
|
* `widgetId`, `hideWrapper`) and the widget-only props (`source`,
|
|
@@ -669,6 +729,9 @@ export default {
|
|
|
669
729
|
if (this.compiledRowClass) {
|
|
670
730
|
inner.rowClass = this.compiledRowClass
|
|
671
731
|
}
|
|
732
|
+
if (this.refLabelColumns.length > 0) {
|
|
733
|
+
inner.columns = this.renderedColumns
|
|
734
|
+
}
|
|
672
735
|
if (this.selfFetchActive) {
|
|
673
736
|
inner.register = this.source.register
|
|
674
737
|
inner.schemaId = this.source.schema
|
|
@@ -804,6 +867,16 @@ export default {
|
|
|
804
867
|
},
|
|
805
868
|
},
|
|
806
869
|
|
|
870
|
+
watch: {
|
|
871
|
+
refTargetsKey() {
|
|
872
|
+
this.loadRefTargets()
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
|
|
876
|
+
mounted() {
|
|
877
|
+
this.loadRefTargets()
|
|
878
|
+
},
|
|
879
|
+
|
|
807
880
|
methods: {
|
|
808
881
|
/**
|
|
809
882
|
* Entry point for every declarative action trigger (row menu or
|
|
@@ -914,6 +987,68 @@ export default {
|
|
|
914
987
|
}
|
|
915
988
|
},
|
|
916
989
|
|
|
990
|
+
/**
|
|
991
|
+
* Where a label column's references point when the column says so
|
|
992
|
+
* itself (`resolve.register` and `resolve.schema`).
|
|
993
|
+
*
|
|
994
|
+
* @param {object} col The column.
|
|
995
|
+
* @return {{register: string, schema: string}|null}
|
|
996
|
+
*/
|
|
997
|
+
explicitTarget(col) {
|
|
998
|
+
const r = col && col.resolve
|
|
999
|
+
if (r && typeof r === 'object' && typeof r.register === 'string' && r.register !== '' && typeof r.schema === 'string' && r.schema !== '') {
|
|
1000
|
+
return { register: r.register, schema: r.schema }
|
|
1001
|
+
}
|
|
1002
|
+
return null
|
|
1003
|
+
},
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Where a label column's references point: the column's `resolve`, else
|
|
1007
|
+
* the source schema's `$ref` for the property, else null (the column
|
|
1008
|
+
* then shows the raw value).
|
|
1009
|
+
*
|
|
1010
|
+
* @param {object} col The column.
|
|
1011
|
+
* @return {{register: string, schema: string}|null}
|
|
1012
|
+
*/
|
|
1013
|
+
refTargetOf(col) {
|
|
1014
|
+
return this.explicitTarget(col) || this.refTargets[col.key] || null
|
|
1015
|
+
},
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* Read the source schema once and note, for each label column without a
|
|
1019
|
+
* `resolve`, the register and schema its property's `$ref` names. A
|
|
1020
|
+
* failed or missing schema leaves those columns showing raw values.
|
|
1021
|
+
*
|
|
1022
|
+
* @return {Promise<void>}
|
|
1023
|
+
* @spec openspec/changes/dashboard-table-reference-labels/specs/dashboard-page/spec.md#requirement-a-dashboard-table-shows-a-referenced-objects-label
|
|
1024
|
+
*/
|
|
1025
|
+
async loadRefTargets() {
|
|
1026
|
+
const keys = this.schemaRefKeys
|
|
1027
|
+
const src = this.source
|
|
1028
|
+
if (keys.length === 0 || !src || typeof src.register !== 'string' || src.register === '' || src.register.startsWith('@') || typeof src.schema !== 'string' || src.schema === '') {
|
|
1029
|
+
return
|
|
1030
|
+
}
|
|
1031
|
+
const store = this.getObjectStore()
|
|
1032
|
+
if (!store || typeof store.fetchSchema !== 'function') {
|
|
1033
|
+
return
|
|
1034
|
+
}
|
|
1035
|
+
const type = resolveObjectOpType(store, { register: src.register, schema: src.schema }, { exactSchema: true })
|
|
1036
|
+
const schema = await store.fetchSchema(type).catch(() => null)
|
|
1037
|
+
if (!schema || typeof schema !== 'object') {
|
|
1038
|
+
return
|
|
1039
|
+
}
|
|
1040
|
+
const fields = fieldsFromSchema(schema, { includeReadOnly: true })
|
|
1041
|
+
const found = {}
|
|
1042
|
+
for (const key of keys) {
|
|
1043
|
+
const field = fields.find((f) => f.key === key)
|
|
1044
|
+
const ref = field && field.reference
|
|
1045
|
+
if (ref && ref.schema !== undefined && ref.schema !== null) {
|
|
1046
|
+
found[key] = { register: ref.register || src.register, schema: String(ref.schema) }
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
this.refTargets = { ...this.refTargets, ...found }
|
|
1050
|
+
},
|
|
1051
|
+
|
|
917
1052
|
/**
|
|
918
1053
|
* The shared object store instance, or null when no Pinia is active
|
|
919
1054
|
* (`dispatchAction` then warns and no-ops).
|
|
@@ -12,6 +12,16 @@ Basic — widget card with title and content:
|
|
|
12
12
|
</div>
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
With an `eyebrow`, a short muted line above the title:
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<div style="width: 320px; height: 160px; position: relative; border: 1px solid var(--color-border); border-radius: 8px; overflow: hidden;">
|
|
19
|
+
<CnWidgetWrapper title="Forecast 13 weeks" eyebrow="Balance per week" :show-title="true">
|
|
20
|
+
<p style="margin: 0; padding: 0 16px;">Week 41</p>
|
|
21
|
+
</CnWidgetWrapper>
|
|
22
|
+
</div>
|
|
23
|
+
```
|
|
24
|
+
|
|
15
25
|
With footer buttons:
|
|
16
26
|
|
|
17
27
|
```vue
|
|
@@ -52,7 +52,15 @@
|
|
|
52
52
|
v-else-if="iconClass"
|
|
53
53
|
:class="iconClass"
|
|
54
54
|
class="cn-widget-wrapper__icon" />
|
|
55
|
-
|
|
55
|
+
<!-- An eyebrow (`eyebrow`) is a muted line above the title:
|
|
56
|
+
"Saldo per week" above "Prognose 13 weken". -->
|
|
57
|
+
<div v-if="resolvedEyebrow" class="cn-widget-wrapper__title-stack">
|
|
58
|
+
<span class="cn-widget-wrapper__eyebrow" data-testid="cn-widget-wrapper-eyebrow">{{ resolvedEyebrow }}</span>
|
|
59
|
+
<h3 :id="titleId" class="cn-widget-wrapper__title">
|
|
60
|
+
{{ resolvedTitle }}
|
|
61
|
+
</h3>
|
|
62
|
+
</div>
|
|
63
|
+
<h3 v-else :id="titleId" class="cn-widget-wrapper__title">
|
|
56
64
|
{{ resolvedTitle }}
|
|
57
65
|
</h3>
|
|
58
66
|
<!-- @slot title-meta Rendered inside the header's left group,
|
|
@@ -234,6 +242,15 @@ export default {
|
|
|
234
242
|
default: () => t('nextcloud-vue', 'Widget'),
|
|
235
243
|
},
|
|
236
244
|
|
|
245
|
+
/**
|
|
246
|
+
* A short muted line above the title ("Saldo per week" above
|
|
247
|
+
* "Prognose 13 weken"), through the host translate. Empty draws none.
|
|
248
|
+
*/
|
|
249
|
+
eyebrow: {
|
|
250
|
+
type: String,
|
|
251
|
+
default: '',
|
|
252
|
+
},
|
|
253
|
+
|
|
237
254
|
/** Whether to show the header with title */
|
|
238
255
|
showTitle: {
|
|
239
256
|
type: Boolean,
|
|
@@ -717,6 +734,16 @@ export default {
|
|
|
717
734
|
return label ? this.effectiveTranslate(label) : ''
|
|
718
735
|
},
|
|
719
736
|
|
|
737
|
+
/**
|
|
738
|
+
* The eyebrow through the host translate, or ''.
|
|
739
|
+
*
|
|
740
|
+
* @return {string}
|
|
741
|
+
* @spec openspec/changes/widget-title-eyebrow/specs/dashboard-page/spec.md#requirement-a-widget-card-can-carry-a-line-above-its-title
|
|
742
|
+
*/
|
|
743
|
+
resolvedEyebrow() {
|
|
744
|
+
return this.eyebrow ? this.effectiveTranslate(this.eyebrow) : ''
|
|
745
|
+
},
|
|
746
|
+
|
|
720
747
|
/**
|
|
721
748
|
* The RENDERED widget title — `displayTitle` run through the host
|
|
722
749
|
* translate function. Kept separate from `displayTitle` on purpose:
|
|
@@ -1152,6 +1179,22 @@ export default {
|
|
|
1152
1179
|
color: var(--cn-widget-icon-color, var(--color-primary-element));
|
|
1153
1180
|
}
|
|
1154
1181
|
|
|
1182
|
+
.cn-widget-wrapper__title-stack {
|
|
1183
|
+
display: flex;
|
|
1184
|
+
flex-direction: column;
|
|
1185
|
+
gap: 2px;
|
|
1186
|
+
min-width: 0;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
.cn-widget-wrapper__eyebrow {
|
|
1190
|
+
font-size: 13px;
|
|
1191
|
+
line-height: 1.3;
|
|
1192
|
+
color: var(--color-text-maxcontrast);
|
|
1193
|
+
white-space: nowrap;
|
|
1194
|
+
overflow: hidden;
|
|
1195
|
+
text-overflow: ellipsis;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1155
1198
|
.cn-widget-wrapper__title {
|
|
1156
1199
|
font-weight: 600;
|
|
1157
1200
|
font-size: 14px;
|
|
@@ -291,6 +291,26 @@ export function useListView(objectTypeOrOptions, options) {
|
|
|
291
291
|
refresh(page)
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Add the next page after the rows already loaded, for a view that shows
|
|
296
|
+
* every row at once (the board). Does nothing on the last page. A refresh
|
|
297
|
+
* started while the page is in flight drops it.
|
|
298
|
+
*
|
|
299
|
+
* @return {Promise<void>}
|
|
300
|
+
*/
|
|
301
|
+
async function loadMore() {
|
|
302
|
+
const current = pagination.value
|
|
303
|
+
const next = Number(current.page || 1) + 1
|
|
304
|
+
if (next > Number(current.pages || 1)) {
|
|
305
|
+
return
|
|
306
|
+
}
|
|
307
|
+
const seq = refreshSeq
|
|
308
|
+
await objectStore.fetchCollection(getType(), buildParams(next), {
|
|
309
|
+
append: true,
|
|
310
|
+
isCurrent: () => seq === refreshSeq,
|
|
311
|
+
})
|
|
312
|
+
}
|
|
313
|
+
|
|
294
314
|
/**
|
|
295
315
|
* Handle page-size change. Resets to page 1.
|
|
296
316
|
*
|
|
@@ -402,6 +422,7 @@ export function useListView(objectTypeOrOptions, options) {
|
|
|
402
422
|
onPageSizeChange,
|
|
403
423
|
// Explicit fetch
|
|
404
424
|
refresh,
|
|
425
|
+
loadMore,
|
|
405
426
|
// The query the list sends (search, sort, facet filters, fixed filters),
|
|
406
427
|
// built from the current state, for an export that must follow the list.
|
|
407
428
|
buildParams,
|
package/src/css/board.css
CHANGED
|
@@ -96,19 +96,24 @@
|
|
|
96
96
|
gap: 8px;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
/* The title is a link drawn as a heading (board DqWerkbord): main text, no
|
|
100
|
+
underline. `!important` because a theme's `a { color; text-decoration }`
|
|
101
|
+
carries it (thematiq), and a bare `a` with `!important` beats any class. */
|
|
102
|
+
.cn-board-view.cn-board-view--board .cn-board-view__card-title,
|
|
103
|
+
.cn-board-view.cn-board-view--board .cn-board-view__card-title:visited {
|
|
100
104
|
flex: 1 1 auto;
|
|
101
105
|
min-width: 0;
|
|
102
106
|
font-size: 15px;
|
|
103
107
|
font-weight: 700;
|
|
104
108
|
line-height: 1.3;
|
|
105
|
-
color: var(--color-main-text);
|
|
106
|
-
text-decoration: none;
|
|
109
|
+
color: var(--color-main-text) !important;
|
|
110
|
+
text-decoration: none !important;
|
|
107
111
|
overflow-wrap: anywhere;
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
.cn-board-view.cn-board-view--board .cn-board-view__card-title:hover {
|
|
111
|
-
|
|
115
|
+
color: var(--color-main-text) !important;
|
|
116
|
+
text-decoration: underline !important;
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
.cn-board-view.cn-board-view--board .cn-board-view__card-title:focus-visible {
|
|
@@ -267,3 +272,59 @@
|
|
|
267
272
|
outline: 2px solid var(--color-primary-element);
|
|
268
273
|
outline-offset: 2px;
|
|
269
274
|
}
|
|
275
|
+
|
|
276
|
+
/*
|
|
277
|
+
* screens-board-reference-columns: a wide board wraps its columns onto more
|
|
278
|
+
* rows (`config.board.wrap`), as many to a row as fit at 240px, instead of
|
|
279
|
+
* one row that scrolls sideways.
|
|
280
|
+
*/
|
|
281
|
+
.cn-board-view.cn-board-view--wrap .cn-board-view__columns {
|
|
282
|
+
display: grid;
|
|
283
|
+
grid-auto-flow: row;
|
|
284
|
+
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
285
|
+
overflow-x: visible;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.cn-board-view.cn-board-view--wrap:not(.cn-board-view--board) .cn-board-view__columns {
|
|
289
|
+
gap: 12px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* A column the dragged card cannot reach fades; the label stays readable. */
|
|
293
|
+
.cn-board-view .cn-board-view__column--unreachable {
|
|
294
|
+
opacity: 0.45;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* The selection checkbox: in the board look's card head, before the title. */
|
|
298
|
+
.cn-board-view .cn-board-view__select {
|
|
299
|
+
flex: none;
|
|
300
|
+
width: 16px;
|
|
301
|
+
height: 16px;
|
|
302
|
+
margin: 2px 0 0;
|
|
303
|
+
accent-color: var(--color-primary-element);
|
|
304
|
+
cursor: pointer;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* Board look: the board draws no checkbox. It shows on a hovered card, on a
|
|
308
|
+
card holding focus (so Tab still reaches it), once anything is selected, and
|
|
309
|
+
always where there is no hover. Collapsed rather than hidden, so it stays in
|
|
310
|
+
the tab order. */
|
|
311
|
+
@media (hover: hover) {
|
|
312
|
+
.cn-board-view.cn-board-view--board:not(.cn-board-view--selecting) .cn-board-view__card:not(:hover, :focus-within) .cn-board-view__select {
|
|
313
|
+
width: 0;
|
|
314
|
+
margin-inline-end: -8px;
|
|
315
|
+
opacity: 0;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* A menu target the card cannot reach: still listed, greyed, with its note. */
|
|
320
|
+
.cn-board-view.cn-board-view--board .cn-board-view__menu-item.cn-board-view__menu-item--blocked {
|
|
321
|
+
color: var(--color-text-maxcontrast);
|
|
322
|
+
cursor: not-allowed;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.cn-board-view .cn-board-view__menu-note {
|
|
326
|
+
margin-inline-start: auto;
|
|
327
|
+
padding-inline-start: 12px;
|
|
328
|
+
font-size: 12px;
|
|
329
|
+
color: var(--color-text-maxcontrast);
|
|
330
|
+
}
|
package/src/css/dialog.css
CHANGED
|
@@ -35,8 +35,10 @@
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/* The header is ours: NcModal's own close button and NcDialog's heading give
|
|
38
|
-
way (the heading stays as the accessible name, visually hidden).
|
|
39
|
-
|
|
38
|
+
way (the heading stays as the accessible name, visually hidden). The mask
|
|
39
|
+
class raises the rule above NcButton's `.button-vue[data-v-…]`, whose
|
|
40
|
+
stylesheet a spawned dialog can load after this one. */
|
|
41
|
+
.modal-mask.cn-dialog-board .modal-container__close {
|
|
40
42
|
display: none;
|
|
41
43
|
}
|
|
42
44
|
|
package/src/css/form-field.css
CHANGED
|
@@ -183,3 +183,17 @@
|
|
|
183
183
|
.cn-look-board .cn-form-page__footer .cn-form-page__primary {
|
|
184
184
|
margin-inline-start: auto;
|
|
185
185
|
}
|
|
186
|
+
|
|
187
|
+
/* A Nextcloud text area or text field with its label inside the field hides
|
|
188
|
+
its placeholder until the field takes focus, so the label and the
|
|
189
|
+
placeholder are never drawn over each other. A theme that forces every
|
|
190
|
+
placeholder visible (thematiq's nldesign system sets
|
|
191
|
+
`::placeholder { opacity: 1 !important }`) drew both: the dossiq DqTaak
|
|
192
|
+
notes field read "Een notitie toevoegen" over "Wat heb je gevonden, wie heb
|
|
193
|
+
je gebeld?". Under the board look the placeholder stays hidden at rest, as
|
|
194
|
+
Nextcloud intends; a field with its label outside keeps its placeholder.
|
|
195
|
+
@spec openspec/changes/board-field-label-over-placeholder/specs/form-field-board-look/spec.md#requirement-a-field-label-and-its-placeholder-are-never-drawn-over-each-other */
|
|
196
|
+
.cn-look-board .textarea__input:not(:focus, .textarea__input--label-outside)::placeholder,
|
|
197
|
+
.cn-look-board .input-field:not(.input-field--label-outside) .input-field__input:not(:focus)::placeholder {
|
|
198
|
+
opacity: 0 !important;
|
|
199
|
+
}
|