@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
|
@@ -207,7 +207,53 @@
|
|
|
207
207
|
<template v-if="$slots['action-items']" #action-items>
|
|
208
208
|
<slot name="action-items" />
|
|
209
209
|
</template>
|
|
210
|
-
<template v-if="$slots['after-search'] || searchInFiles" #after-search>
|
|
210
|
+
<template v-if="$slots['after-search'] || searchInFiles || boardControlsShown" #after-search>
|
|
211
|
+
<!-- Board view controls, after the search (screens-board-reference-columns):
|
|
212
|
+
the narrowing select ("Case type:"), the column switch ("Columns:
|
|
213
|
+
status | type | assignee") and the board's hint sentence. -->
|
|
214
|
+
<template v-if="boardControlsShown">
|
|
215
|
+
<label
|
|
216
|
+
v-if="boardNarrow"
|
|
217
|
+
class="cn-index-page__board-control"
|
|
218
|
+
data-testid="cn-board-narrow">
|
|
219
|
+
<span class="cn-index-page__board-control-label">{{ boardNarrowLabel }}</span>
|
|
220
|
+
<select
|
|
221
|
+
class="cn-index-page__board-select"
|
|
222
|
+
data-testid="cn-board-narrow-select"
|
|
223
|
+
:value="boardNarrowValue"
|
|
224
|
+
@change="onBoardNarrowChange($event.target.value)">
|
|
225
|
+
<option value="">{{ boardNarrowAllLabel }}</option>
|
|
226
|
+
<option
|
|
227
|
+
v-for="option in boardNarrowOptions"
|
|
228
|
+
:key="`narrow-${option.value}`"
|
|
229
|
+
:value="option.value">
|
|
230
|
+
{{ option.label }}
|
|
231
|
+
</option>
|
|
232
|
+
</select>
|
|
233
|
+
</label>
|
|
234
|
+
<label
|
|
235
|
+
v-if="boardColumnFields.length > 1"
|
|
236
|
+
class="cn-index-page__board-control"
|
|
237
|
+
data-testid="cn-board-column-switch">
|
|
238
|
+
<span class="cn-index-page__board-control-label">{{ boardColumnSwitchLabel }}</span>
|
|
239
|
+
<select
|
|
240
|
+
class="cn-index-page__board-select cn-index-page__board-select--strong"
|
|
241
|
+
data-testid="cn-board-column-switch-select"
|
|
242
|
+
:value="boardColumnField"
|
|
243
|
+
@change="onBoardColumnFieldChange($event.target.value)">
|
|
244
|
+
<option
|
|
245
|
+
v-for="entry in boardColumnFields"
|
|
246
|
+
:key="`colfield-${entry.field}`"
|
|
247
|
+
:value="entry.field">
|
|
248
|
+
{{ cnTranslate(entry.label) }}
|
|
249
|
+
</option>
|
|
250
|
+
</select>
|
|
251
|
+
</label>
|
|
252
|
+
<span
|
|
253
|
+
v-if="board.hint"
|
|
254
|
+
class="cn-index-page__board-hint"
|
|
255
|
+
data-testid="cn-board-hint">{{ cnTranslate(board.hint) }}</span>
|
|
256
|
+
</template>
|
|
211
257
|
<NcCheckboxRadioSwitch
|
|
212
258
|
v-if="searchInFiles"
|
|
213
259
|
:modelValue="contentSearch"
|
|
@@ -361,6 +407,17 @@
|
|
|
361
407
|
</button>
|
|
362
408
|
</div>
|
|
363
409
|
|
|
410
|
+
<!-- Header actions of `type: "open-form"` or `"open-modal"`: this
|
|
411
|
+
instance draws nothing and owns the create dialog, as on a detail
|
|
412
|
+
page, so a header button or menu entry naming one opens it. -->
|
|
413
|
+
<CnActionButtons
|
|
414
|
+
v-if="dialogHeaderActions.length > 0"
|
|
415
|
+
:actions="dialogHeaderActions"
|
|
416
|
+
display="menu"
|
|
417
|
+
data-testid="cn-index-header-dialog-actions"
|
|
418
|
+
@entries="dialogHeaderRuns = $event"
|
|
419
|
+
@created="onHeaderActionCreated" />
|
|
420
|
+
|
|
364
421
|
<!-- Quick edit: a few fields of one row, over the list, with the list
|
|
365
422
|
keeping its place. -->
|
|
366
423
|
<CnQuickEditDialog
|
|
@@ -786,8 +843,13 @@
|
|
|
786
843
|
<CnBoardView
|
|
787
844
|
v-else-if="currentViewMode === 'board'"
|
|
788
845
|
:rows="displayObjects"
|
|
789
|
-
:statusFieldSchema="
|
|
790
|
-
:statusField="
|
|
846
|
+
:statusFieldSchema="boardFieldSchema"
|
|
847
|
+
:statusField="boardColumnField"
|
|
848
|
+
:columnKeyOf="boardColumnKeyOf"
|
|
849
|
+
:wrapColumns="board.wrap === true"
|
|
850
|
+
:selectable="selectable"
|
|
851
|
+
:selectedIds="internalSelectedIds"
|
|
852
|
+
:allowedMoves="boardAllowedMoves"
|
|
791
853
|
:cardFields="board.cardFields || []"
|
|
792
854
|
:swimlaneField="board.swimlaneField || ''"
|
|
793
855
|
:dueRule="board.dueRule || null"
|
|
@@ -797,8 +859,9 @@
|
|
|
797
859
|
:sumFormat="boardSumFormat"
|
|
798
860
|
:columnLimit="board.columnLimit || 0"
|
|
799
861
|
:rowKey="rowKey"
|
|
800
|
-
:runTransition="
|
|
862
|
+
:runTransition="boardRunTransition"
|
|
801
863
|
:paged="isPaged"
|
|
864
|
+
@select="onSelect"
|
|
802
865
|
@loadMore="onBoardLoadMore"
|
|
803
866
|
@cardClick="onRowClick"
|
|
804
867
|
@cardAuxClick="onRowAuxClick"
|
|
@@ -959,9 +1022,27 @@
|
|
|
959
1022
|
{{ t('nextcloud-vue', 'File matches are limited to the best 50.') }}
|
|
960
1023
|
</p>
|
|
961
1024
|
|
|
1025
|
+
<!-- The board view's footer: it holds every row it loaded, so it
|
|
1026
|
+
counts them and offers the next batch instead of pages. -->
|
|
1027
|
+
<div
|
|
1028
|
+
v-if="boardLoadsAll && boardLoadCounts.total > 0"
|
|
1029
|
+
class="cn-index-page__board-load"
|
|
1030
|
+
data-testid="cn-index-board-load">
|
|
1031
|
+
<span class="cn-index-page__board-load-count" data-testid="cn-index-board-load-count">
|
|
1032
|
+
{{ t('nextcloud-vue', 'Showing {count} of {total}', { count: boardLoadCounts.shown, total: boardLoadCounts.total }) }}
|
|
1033
|
+
</span>
|
|
1034
|
+
<NcButton
|
|
1035
|
+
v-if="isPaged"
|
|
1036
|
+
:disabled="effectiveLoading"
|
|
1037
|
+
data-testid="cn-index-board-load-more"
|
|
1038
|
+
@click="onBoardLoadMore">
|
|
1039
|
+
{{ t('nextcloud-vue', 'Load more') }}
|
|
1040
|
+
</NcButton>
|
|
1041
|
+
</div>
|
|
1042
|
+
|
|
962
1043
|
<!-- Pagination -->
|
|
963
1044
|
<CnPagination
|
|
964
|
-
v-if="effectivePagination && (effectivePagination.pages > 1 || (isBoardLook && effectivePagination.total > 0))"
|
|
1045
|
+
v-else-if="effectivePagination && (effectivePagination.pages > 1 || (isBoardLook && effectivePagination.total > 0))"
|
|
965
1046
|
:variant="isBoardLook ? 'board' : ''"
|
|
966
1047
|
:footerNote="footerNote ? cnTranslate(footerNote) : footerNote"
|
|
967
1048
|
:currentPage="effectivePagination.page || 1"
|
|
@@ -1053,7 +1134,7 @@
|
|
|
1053
1134
|
|
|
1054
1135
|
<script>
|
|
1055
1136
|
import { getCurrentUser } from '@nextcloud/auth'
|
|
1056
|
-
import { translate as t } from '@nextcloud/l10n'
|
|
1137
|
+
import { translatePlural as n, translate as t } from '@nextcloud/l10n'
|
|
1057
1138
|
import { NcActionButton, NcActionCaption, NcActionCheckbox, NcActionLink, NcActions, NcActionSeparator, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'
|
|
1058
1139
|
import { getCurrentInstance, inject, markRaw, ref } from 'vue'
|
|
1059
1140
|
import AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'
|
|
@@ -1083,6 +1164,16 @@ import { METADATA_COLUMNS } from '../../constants/metadata.js'
|
|
|
1083
1164
|
import { useObjectStore } from '../../store/useObjectStore.js'
|
|
1084
1165
|
import { followItemActionLink, resolveItemActionLink, routeHref } from '../../utils/actionLink.js'
|
|
1085
1166
|
import { buildOnSuccessRoute, resolveRegisteredHandler } from '../../utils/actionsDispatcher.js'
|
|
1167
|
+
import {
|
|
1168
|
+
buildReferenceStages,
|
|
1169
|
+
buildValueStages,
|
|
1170
|
+
columnFieldsOf,
|
|
1171
|
+
columnKeyOfRow,
|
|
1172
|
+
fetchReferenceObjects,
|
|
1173
|
+
referenceTargetOf,
|
|
1174
|
+
refIdOf,
|
|
1175
|
+
resolveDropValue,
|
|
1176
|
+
} from '../../utils/boardReferenceColumns.js'
|
|
1086
1177
|
import { reportBindingProblems } from '../../utils/diagnostics.js'
|
|
1087
1178
|
import { fetchFilterCounts } from '../../utils/fetchFilterCounts.js'
|
|
1088
1179
|
import { buildExportUrl } from '../../utils/indexExportHelpers.js'
|
|
@@ -1092,6 +1183,7 @@ import { resolveClaimedTeams, resolveClaimTokens, splitViewsIntoTabs, viewAsTab,
|
|
|
1092
1183
|
import { LIST_SHORTCUTS, listPaletteCommands, shortcutFor } from '../../utils/listShortcuts.js'
|
|
1093
1184
|
import { multiKeySort } from '../../utils/multiKeySort.js'
|
|
1094
1185
|
import { OBJECTS_CHANGED_EVENT } from '../../utils/objectSignals.js'
|
|
1186
|
+
import { objectUrlOf, patchObject } from '../../utils/objectWrite.js'
|
|
1095
1187
|
import { withPersonalLenses } from '../../utils/personalLenses.js'
|
|
1096
1188
|
import { resolveDeepTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js'
|
|
1097
1189
|
import { resolveRowActions } from '../../utils/resolveRowActions.js'
|
|
@@ -1104,6 +1196,7 @@ import { buildRouteQueryFromViewState, buildViewCreatePayload, extractViewState,
|
|
|
1104
1196
|
import { columnsFromSchema, fieldsFromSchema } from '../../utils/schema.js'
|
|
1105
1197
|
import { resolveScopeLayout } from '../../utils/scopeListLayout.js'
|
|
1106
1198
|
import { dispatchObjectCreated } from '../../utils/walkthroughSignals.js'
|
|
1199
|
+
import { CnActionButtons } from '../CnActionButtons/index.js'
|
|
1107
1200
|
import { CnActionsBar } from '../CnActionsBar/index.js'
|
|
1108
1201
|
import { CnAdvancedFormDialog } from '../CnAdvancedFormDialog/index.js'
|
|
1109
1202
|
import { CnBoardView } from '../CnBoardView/index.js'
|
|
@@ -1140,7 +1233,7 @@ import { orderColumns, personalColumnsKey, reconcilePersonalColumns } from './pe
|
|
|
1140
1233
|
import { createSelfModeActions, resolveRowTarget } from './selfModeActions.js'
|
|
1141
1234
|
import { applyRowPatches, normalisePaneWidth, rowIdOf, splitLayoutFor } from './splitView.js'
|
|
1142
1235
|
import { useNamedSource } from './useNamedSource.js'
|
|
1143
|
-
import { useSelfFetchList } from './useSelfFetchList.js'
|
|
1236
|
+
import { BOARD_PAGE_SIZE, useSelfFetchList } from './useSelfFetchList.js'
|
|
1144
1237
|
|
|
1145
1238
|
/** Rows fetched for one month in calendar mode. */
|
|
1146
1239
|
const CALENDAR_PAGE_SIZE = 200
|
|
@@ -1394,6 +1487,7 @@ export default {
|
|
|
1394
1487
|
NcCheckboxRadioSwitch,
|
|
1395
1488
|
CnPageHeader,
|
|
1396
1489
|
CnQuickFilterBar,
|
|
1490
|
+
CnActionButtons,
|
|
1397
1491
|
CnActionsBar,
|
|
1398
1492
|
DotsHorizontal,
|
|
1399
1493
|
CnIcon,
|
|
@@ -1440,6 +1534,8 @@ export default {
|
|
|
1440
1534
|
*/
|
|
1441
1535
|
inject: {
|
|
1442
1536
|
cnCustomComponents: { default: () => ({}) },
|
|
1537
|
+
/** The app id CnAppRoot provides, for the plural form of `countSubtitle`. */
|
|
1538
|
+
cnAppId: { default: '' },
|
|
1443
1539
|
/**
|
|
1444
1540
|
* The app manifest, provided by CnAppRoot. A column with `labelField`
|
|
1445
1541
|
* and `link: true` finds the referenced schema's detail page here.
|
|
@@ -1526,10 +1622,17 @@ export default {
|
|
|
1526
1622
|
* shows. Manifest key `config.countSubtitle`. Goes through the host
|
|
1527
1623
|
* translate function.
|
|
1528
1624
|
*
|
|
1625
|
+
* `{ singular, plural }` picks the form by the total ("1 invoice",
|
|
1626
|
+
* "12 invoices") through the app's plural translation
|
|
1627
|
+
* (`translatePlural` with the app id CnAppRoot provides), so a
|
|
1628
|
+
* language with other plural rules gets its own forms.
|
|
1629
|
+
*
|
|
1529
1630
|
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-an-index-page-title-is-a-manifest-key
|
|
1631
|
+
* @spec openspec/changes/index-count-plural/specs/index-header/spec.md#requirement-the-count-line-takes-a-singular-and-a-plural-form
|
|
1632
|
+
* @type {string|{singular: string, plural: string}}
|
|
1530
1633
|
*/
|
|
1531
1634
|
countSubtitle: {
|
|
1532
|
-
type: String,
|
|
1635
|
+
type: [String, Object],
|
|
1533
1636
|
default: '',
|
|
1534
1637
|
},
|
|
1535
1638
|
|
|
@@ -2310,10 +2413,14 @@ export default {
|
|
|
2310
2413
|
default: () => [],
|
|
2311
2414
|
},
|
|
2312
2415
|
|
|
2313
|
-
/**
|
|
2416
|
+
/**
|
|
2417
|
+
* Text shown when no items found. The default is the library's own
|
|
2418
|
+
* string, so it reads in the user's language; a page's own text goes
|
|
2419
|
+
* through the app's translate function.
|
|
2420
|
+
*/
|
|
2314
2421
|
emptyText: {
|
|
2315
2422
|
type: String,
|
|
2316
|
-
default: 'No items found',
|
|
2423
|
+
default: () => t('nextcloud-vue', 'No items found'),
|
|
2317
2424
|
},
|
|
2318
2425
|
|
|
2319
2426
|
/**
|
|
@@ -3335,6 +3442,7 @@ export default {
|
|
|
3335
3442
|
'add',
|
|
3336
3443
|
'apply-view',
|
|
3337
3444
|
'board-move',
|
|
3445
|
+
'board-column-field-change',
|
|
3338
3446
|
'bulk-action',
|
|
3339
3447
|
'clear-filters',
|
|
3340
3448
|
'columns-change',
|
|
@@ -3446,10 +3554,21 @@ export default {
|
|
|
3446
3554
|
data() {
|
|
3447
3555
|
return {
|
|
3448
3556
|
currentViewMode: this.viewMode,
|
|
3557
|
+
/** The column field the reader picked in the board's column switch; '' = the default. */
|
|
3558
|
+
boardColumnFieldChoice: '',
|
|
3559
|
+
/** The rows a reference column field is built from, by field. */
|
|
3560
|
+
boardRefs: {},
|
|
3561
|
+
/** The options of the board's narrowing select (`board.narrow`). */
|
|
3562
|
+
boardNarrowOptions: [],
|
|
3563
|
+
/** The menu entries CnActionButtons reports for the dialog header actions, each with its `run()`. */
|
|
3564
|
+
dialogHeaderRuns: [],
|
|
3449
3565
|
/** The visible calendar window `{ rangeStart, rangeEnd }` (ISO dates), or null outside calendar mode. */
|
|
3450
3566
|
calendarRange: null,
|
|
3451
3567
|
/** The page size to restore when leaving calendar mode. */
|
|
3452
3568
|
calendarPrevPageSize: null,
|
|
3569
|
+
// The table's page size while the board view holds the list at
|
|
3570
|
+
// BOARD_PAGE_SIZE; restored on leaving the board.
|
|
3571
|
+
boardPrevPageSize: this.viewMode === 'board' ? ((this.pagination && this.pagination.limit) || 20) : null,
|
|
3453
3572
|
/** Resolved labels of reference columns: `{ [columnKey]: { [id]: label|null } }`. */
|
|
3454
3573
|
refLabels: {},
|
|
3455
3574
|
/** Count per tab-strip index, for the entries that asked for one; null = none. */
|
|
@@ -3670,6 +3789,24 @@ export default {
|
|
|
3670
3789
|
*
|
|
3671
3790
|
* @return {Array<object>}
|
|
3672
3791
|
*/
|
|
3792
|
+
/**
|
|
3793
|
+
* The header actions that open a dialog: `type: "open-form"` (the
|
|
3794
|
+
* schema-driven create form, as the navigation's primary action opens
|
|
3795
|
+
* it) or `type: "open-modal"`, without a `handler` of their own.
|
|
3796
|
+
* Reserved ids are left out, as in `mergedHeaderActions`.
|
|
3797
|
+
*
|
|
3798
|
+
* @spec openspec/changes/index-header-open-form/specs/index-header/spec.md#requirement-an-index-header-action-can-open-the-create-form
|
|
3799
|
+
* @return {Array<object>}
|
|
3800
|
+
*/
|
|
3801
|
+
dialogHeaderActions() {
|
|
3802
|
+
const reserved = new Set(['refresh', 'import', 'export', 'copy', 'delete'])
|
|
3803
|
+
return (this.headerActions || []).filter((entry) => entry
|
|
3804
|
+
&& typeof entry.id === 'string'
|
|
3805
|
+
&& !reserved.has(entry.id)
|
|
3806
|
+
&& (entry.handler === undefined || entry.handler === null || entry.handler === '')
|
|
3807
|
+
&& (entry.type === 'open-form' || entry.type === 'open-modal'))
|
|
3808
|
+
},
|
|
3809
|
+
|
|
3673
3810
|
mergedHeaderActions() {
|
|
3674
3811
|
const reserved = new Set(['refresh', 'import', 'export', 'copy', 'delete'])
|
|
3675
3812
|
const merged = []
|
|
@@ -4022,6 +4159,241 @@ export default {
|
|
|
4022
4159
|
})
|
|
4023
4160
|
},
|
|
4024
4161
|
|
|
4162
|
+
/**
|
|
4163
|
+
* The column fields the board offers (`board.columnFields`), for the
|
|
4164
|
+
* column switch (screens-board-reference-columns).
|
|
4165
|
+
*
|
|
4166
|
+
* @return {Array<object>} The normalised fields; empty for a board on `statusField` only.
|
|
4167
|
+
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-board-can-switch-the-field-its-columns-come-from
|
|
4168
|
+
*/
|
|
4169
|
+
boardColumnFields() {
|
|
4170
|
+
return columnFieldsOf(this.board)
|
|
4171
|
+
},
|
|
4172
|
+
|
|
4173
|
+
/**
|
|
4174
|
+
* The column field in use: the reader's pick, else the one on
|
|
4175
|
+
* `statusField`, else the first. Null on a board without `columnFields`.
|
|
4176
|
+
*
|
|
4177
|
+
* @return {object|null} The normalised column field.
|
|
4178
|
+
*/
|
|
4179
|
+
boardActiveColumnField() {
|
|
4180
|
+
const fields = this.boardColumnFields
|
|
4181
|
+
if (fields.length === 0) {
|
|
4182
|
+
return null
|
|
4183
|
+
}
|
|
4184
|
+
return fields.find((entry) => entry.field === this.boardColumnFieldChoice)
|
|
4185
|
+
|| fields.find((entry) => entry.field === this.board?.statusField)
|
|
4186
|
+
|| fields[0]
|
|
4187
|
+
},
|
|
4188
|
+
|
|
4189
|
+
/** @return {string} The row field the columns come from. */
|
|
4190
|
+
boardColumnField() {
|
|
4191
|
+
return this.boardActiveColumnField?.field || this.board?.statusField || 'status'
|
|
4192
|
+
},
|
|
4193
|
+
|
|
4194
|
+
/**
|
|
4195
|
+
* The parent the board is narrowed to: the single value of the page
|
|
4196
|
+
* filter on the reference's `narrowBy.rowField`, '' when none or several.
|
|
4197
|
+
*
|
|
4198
|
+
* @return {string} The parent id.
|
|
4199
|
+
*/
|
|
4200
|
+
boardNarrowValue() {
|
|
4201
|
+
const field = this.board?.narrow?.field || this.boardActiveColumnField?.source?.narrowBy?.rowField
|
|
4202
|
+
if (!field) {
|
|
4203
|
+
return ''
|
|
4204
|
+
}
|
|
4205
|
+
const current = this.effectiveActiveFilters?.[field]
|
|
4206
|
+
const values = Array.isArray(current) ? current : (current === undefined || current === null || current === '' ? [] : [current])
|
|
4207
|
+
return values.length === 1 ? refIdOf(values[0]) : ''
|
|
4208
|
+
},
|
|
4209
|
+
|
|
4210
|
+
/**
|
|
4211
|
+
* The stages of a reference or values column field, or null for a
|
|
4212
|
+
* field the schema's enum or lifecycle states back.
|
|
4213
|
+
*
|
|
4214
|
+
* @return {object|null} `{ states, keyByValue, refsByKey }`.
|
|
4215
|
+
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references
|
|
4216
|
+
*/
|
|
4217
|
+
boardStages() {
|
|
4218
|
+
const active = this.boardActiveColumnField
|
|
4219
|
+
if (!active) {
|
|
4220
|
+
return null
|
|
4221
|
+
}
|
|
4222
|
+
if (active.kind === 'values') {
|
|
4223
|
+
return buildValueStages({
|
|
4224
|
+
rows: this.displayObjects,
|
|
4225
|
+
field: active.field,
|
|
4226
|
+
valueLabels: active.valueLabels,
|
|
4227
|
+
emptyLabel: active.emptyLabel ? this.cnTranslate(active.emptyLabel) : t('nextcloud-vue', 'Nobody'),
|
|
4228
|
+
})
|
|
4229
|
+
}
|
|
4230
|
+
if (active.kind !== 'reference') {
|
|
4231
|
+
return null
|
|
4232
|
+
}
|
|
4233
|
+
const source = active.source || {}
|
|
4234
|
+
const narrowBy = source.narrowBy && typeof source.narrowBy === 'object' ? source.narrowBy : null
|
|
4235
|
+
return buildReferenceStages({
|
|
4236
|
+
refs: this.boardRefs[active.field] || [],
|
|
4237
|
+
labelField: source.labelField || '',
|
|
4238
|
+
orderField: source.orderField || '',
|
|
4239
|
+
colorField: source.colorField || '',
|
|
4240
|
+
mergeBy: source.mergeBy || '',
|
|
4241
|
+
narrowBy,
|
|
4242
|
+
narrowValue: narrowBy ? this.boardNarrowValue : '',
|
|
4243
|
+
})
|
|
4244
|
+
},
|
|
4245
|
+
|
|
4246
|
+
/**
|
|
4247
|
+
* The field schema the board reads its columns from: the stages of a
|
|
4248
|
+
* reference or values field as lifecycle `states`, else the schema's
|
|
4249
|
+
* own property.
|
|
4250
|
+
*
|
|
4251
|
+
* @return {?object} The field schema, or null.
|
|
4252
|
+
*/
|
|
4253
|
+
boardFieldSchema() {
|
|
4254
|
+
if (this.boardStages) {
|
|
4255
|
+
return { states: this.boardStages.states }
|
|
4256
|
+
}
|
|
4257
|
+
const field = this.boardColumnField
|
|
4258
|
+
return this.effectiveSchema?.properties?.[field] || null
|
|
4259
|
+
},
|
|
4260
|
+
|
|
4261
|
+
/**
|
|
4262
|
+
* The column a card sits in, for a reference or values field.
|
|
4263
|
+
*
|
|
4264
|
+
* @return {((row: object) => string)|null} The mapper, or null.
|
|
4265
|
+
*/
|
|
4266
|
+
boardColumnKeyOf() {
|
|
4267
|
+
const stages = this.boardStages
|
|
4268
|
+
if (!stages) {
|
|
4269
|
+
return null
|
|
4270
|
+
}
|
|
4271
|
+
const field = this.boardColumnField
|
|
4272
|
+
return (row) => columnKeyOfRow(row, field, stages.keyByValue)
|
|
4273
|
+
},
|
|
4274
|
+
|
|
4275
|
+
/**
|
|
4276
|
+
* The move the board runs on a drop or a menu pick.
|
|
4277
|
+
*
|
|
4278
|
+
* A named handler (`moveHandler`, from the app's registry) gets
|
|
4279
|
+
* `{ card, toKey, field, value, target }` and owns the write; the
|
|
4280
|
+
* status of a case goes through the app's transition this way. A
|
|
4281
|
+
* reference or values field without one has its value written on the
|
|
4282
|
+
* row (PATCH). `readOnly` gives no move. A board on `statusField` with
|
|
4283
|
+
* neither keeps the `runTransition` prop.
|
|
4284
|
+
*
|
|
4285
|
+
* @return {((move: {card: object, toKey: string}) => Promise<object>)|null} The move, or null for a read-only board.
|
|
4286
|
+
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-drop-writes-the-reference
|
|
4287
|
+
*/
|
|
4288
|
+
boardRunTransition() {
|
|
4289
|
+
const active = this.boardActiveColumnField
|
|
4290
|
+
if (active?.readOnly) {
|
|
4291
|
+
return null
|
|
4292
|
+
}
|
|
4293
|
+
const onStatusField = !active || active.field === this.board?.statusField
|
|
4294
|
+
const name = active?.moveHandler || (onStatusField ? (this.board?.moveHandler || '') : '')
|
|
4295
|
+
const handler = name ? resolveRegisteredHandler(name, this.effectiveRegistry, this.resolvedCustomComponents) : null
|
|
4296
|
+
if (name && typeof handler !== 'function') {
|
|
4297
|
+
return null
|
|
4298
|
+
}
|
|
4299
|
+
const stages = this.boardStages
|
|
4300
|
+
if (!handler && !stages) {
|
|
4301
|
+
return this.runTransition
|
|
4302
|
+
}
|
|
4303
|
+
const field = this.boardColumnField
|
|
4304
|
+
const kind = active?.kind || 'schema'
|
|
4305
|
+
const narrowBy = active?.source?.narrowBy || null
|
|
4306
|
+
return async ({ card, toKey }) => {
|
|
4307
|
+
const drop = stages
|
|
4308
|
+
? resolveDropValue({ card, toKey, kind, refsByKey: stages.refsByKey, narrowBy })
|
|
4309
|
+
: { value: toKey, target: null }
|
|
4310
|
+
if (drop === null) {
|
|
4311
|
+
throw new Error(t('nextcloud-vue', 'This card cannot move to that column.'))
|
|
4312
|
+
}
|
|
4313
|
+
if (handler) {
|
|
4314
|
+
return handler({ card, toKey, field, value: drop.value, target: drop.target })
|
|
4315
|
+
}
|
|
4316
|
+
const id = card?.id ?? card?.['@self']?.id ?? card?.[this.rowKey]
|
|
4317
|
+
const url = objectUrlOf(this.register, this.exportSchemaSlug, id)
|
|
4318
|
+
if (url === '') {
|
|
4319
|
+
throw new Error(t('nextcloud-vue', 'This card cannot move to that column.'))
|
|
4320
|
+
}
|
|
4321
|
+
return patchObject(url, { [field]: drop.value })
|
|
4322
|
+
}
|
|
4323
|
+
},
|
|
4324
|
+
|
|
4325
|
+
/**
|
|
4326
|
+
* Where a card may go, from the app's `moveTargetsHandler`: it gets
|
|
4327
|
+
* `{ card, field }` and answers the values (referenced ids) the card
|
|
4328
|
+
* can reach; the board maps them to its columns.
|
|
4329
|
+
*
|
|
4330
|
+
* @return {((card: object) => Promise<Array<string>|null>)|null} The question, or null.
|
|
4331
|
+
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-the-board-shows-where-a-card-can-go
|
|
4332
|
+
*/
|
|
4333
|
+
boardAllowedMoves() {
|
|
4334
|
+
const active = this.boardActiveColumnField
|
|
4335
|
+
const onStatusField = !active || active.field === this.board?.statusField
|
|
4336
|
+
const name = active?.moveTargetsHandler || (onStatusField ? (this.board?.moveTargetsHandler || '') : '')
|
|
4337
|
+
const handler = name ? resolveRegisteredHandler(name, this.effectiveRegistry, this.resolvedCustomComponents) : null
|
|
4338
|
+
if (typeof handler !== 'function' || this.boardRunTransition === null) {
|
|
4339
|
+
return null
|
|
4340
|
+
}
|
|
4341
|
+
const field = this.boardColumnField
|
|
4342
|
+
const stages = this.boardStages
|
|
4343
|
+
return async (card) => {
|
|
4344
|
+
const values = await handler({ card, field })
|
|
4345
|
+
if (!Array.isArray(values)) {
|
|
4346
|
+
return null
|
|
4347
|
+
}
|
|
4348
|
+
return values.map((value) => {
|
|
4349
|
+
const id = refIdOf(value)
|
|
4350
|
+
return stages && stages.keyByValue.has(id) ? stages.keyByValue.get(id) : id
|
|
4351
|
+
})
|
|
4352
|
+
}
|
|
4353
|
+
},
|
|
4354
|
+
|
|
4355
|
+
/** @return {object|null} The board's narrowing select (`board.narrow`). */
|
|
4356
|
+
boardNarrow() {
|
|
4357
|
+
const narrow = this.board?.narrow
|
|
4358
|
+
return narrow && typeof narrow === 'object' && typeof narrow.field === 'string' && narrow.field !== '' ? narrow : null
|
|
4359
|
+
},
|
|
4360
|
+
|
|
4361
|
+
/** @return {string} The narrowing select's label, with its colon. */
|
|
4362
|
+
boardNarrowLabel() {
|
|
4363
|
+
const narrow = this.boardNarrow || {}
|
|
4364
|
+
const prop = (this.effectiveSchema?.properties || {})[narrow.field] || {}
|
|
4365
|
+
return t('nextcloud-vue', '{label}:', { label: this.cnTranslate(narrow.label || prop.title || narrow.field || '') })
|
|
4366
|
+
},
|
|
4367
|
+
|
|
4368
|
+
/** @return {string} The narrowing select's "all" option. */
|
|
4369
|
+
boardNarrowAllLabel() {
|
|
4370
|
+
return this.boardNarrow?.allLabel ? this.cnTranslate(this.boardNarrow.allLabel) : t('nextcloud-vue', 'All')
|
|
4371
|
+
},
|
|
4372
|
+
|
|
4373
|
+
/** @return {string} The column switch's label, with its colon. */
|
|
4374
|
+
boardColumnSwitchLabel() {
|
|
4375
|
+
const label = this.board?.columnSwitchLabel ? this.cnTranslate(this.board.columnSwitchLabel) : t('nextcloud-vue', 'Columns')
|
|
4376
|
+
return t('nextcloud-vue', '{label}:', { label })
|
|
4377
|
+
},
|
|
4378
|
+
|
|
4379
|
+
/** @return {boolean} Whether the board view draws its controls row. */
|
|
4380
|
+
boardControlsShown() {
|
|
4381
|
+
return this.currentViewMode === 'board'
|
|
4382
|
+
&& (this.boardColumnFields.length > 1 || this.boardNarrow !== null || Boolean(this.board?.hint))
|
|
4383
|
+
},
|
|
4384
|
+
|
|
4385
|
+
/**
|
|
4386
|
+
* What the board needs fetched, as one key the watcher reacts to.
|
|
4387
|
+
*
|
|
4388
|
+
* @return {string} The key, '' outside the board view.
|
|
4389
|
+
*/
|
|
4390
|
+
boardFetchKey() {
|
|
4391
|
+
if (this.currentViewMode !== 'board') {
|
|
4392
|
+
return ''
|
|
4393
|
+
}
|
|
4394
|
+
return [this.boardColumnField, this.boardActiveColumnField?.kind || '', this.effectiveSchema ? 1 : 0, this.boardNarrow ? this.boardNarrow.field : ''].join('|')
|
|
4395
|
+
},
|
|
4396
|
+
|
|
4025
4397
|
/**
|
|
4026
4398
|
* The status field's schema, for the board's columns.
|
|
4027
4399
|
*
|
|
@@ -4068,9 +4440,36 @@ export default {
|
|
|
4068
4440
|
* @return {boolean} True when there is more than this page.
|
|
4069
4441
|
*/
|
|
4070
4442
|
isPaged() {
|
|
4443
|
+
if (this.boardLoadsAll) {
|
|
4444
|
+
const loaded = this.effectivePagination || {}
|
|
4445
|
+
return Number(loaded.page || 1) < Number(loaded.pages || 1)
|
|
4446
|
+
}
|
|
4071
4447
|
return Number(this.pagination?.pages || 1) > 1
|
|
4072
4448
|
},
|
|
4073
4449
|
|
|
4450
|
+
/**
|
|
4451
|
+
* Whether the board view gathers every row itself: in self-fetch mode
|
|
4452
|
+
* it adds page after page (`list.loadMore`) instead of paging, and
|
|
4453
|
+
* draws its own footer in place of the pagination.
|
|
4454
|
+
*
|
|
4455
|
+
* @return {boolean} True for a self-fetching page in board view.
|
|
4456
|
+
* @spec openspec/changes/board-loads-every-row/specs/board-view/spec.md#requirement-the-index-board-shows-every-matching-row
|
|
4457
|
+
*/
|
|
4458
|
+
boardLoadsAll() {
|
|
4459
|
+
return this.currentViewMode === 'board' && this.isSelfFetchMode && !this.isNamedSource && typeof this.list.loadMore === 'function'
|
|
4460
|
+
},
|
|
4461
|
+
|
|
4462
|
+
/**
|
|
4463
|
+
* The rows the board holds against the rows that match, for the
|
|
4464
|
+
* board's footer.
|
|
4465
|
+
*
|
|
4466
|
+
* @return {{shown: number, total: number}} The counts.
|
|
4467
|
+
*/
|
|
4468
|
+
boardLoadCounts() {
|
|
4469
|
+
const shown = this.effectiveObjects.length
|
|
4470
|
+
return { shown, total: Math.max(shown, Number(this.effectivePagination?.total || 0)) }
|
|
4471
|
+
},
|
|
4472
|
+
|
|
4074
4473
|
/**
|
|
4075
4474
|
* The CnFolderSidebar source. A `register` source is fetched by this
|
|
4076
4475
|
* component and handed to CnFolderSidebar as a `custom` folder list.
|
|
@@ -5873,13 +6272,15 @@ export default {
|
|
|
5873
6272
|
if (!this.countText && !this.countSubtitle) {
|
|
5874
6273
|
return t('nextcloud-vue', '{shown} of {total}', { shown, total })
|
|
5875
6274
|
}
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
6275
|
+
if (this.countText) {
|
|
6276
|
+
return this.cnTranslate(this.countText)
|
|
6277
|
+
.replace('{shown}', String(shown))
|
|
6278
|
+
.replace('{total}', String(total))
|
|
6279
|
+
}
|
|
6280
|
+
return this.countLine(this.countSubtitle, total, shown)
|
|
5880
6281
|
}
|
|
5881
6282
|
if (this.countSubtitle && typeof total === 'number' && total >= 0) {
|
|
5882
|
-
return this.
|
|
6283
|
+
return this.countLine(this.countSubtitle, total, null)
|
|
5883
6284
|
}
|
|
5884
6285
|
return this.description
|
|
5885
6286
|
},
|
|
@@ -6045,6 +6446,19 @@ export default {
|
|
|
6045
6446
|
},
|
|
6046
6447
|
|
|
6047
6448
|
watch: {
|
|
6449
|
+
'$route.query._view': function() {
|
|
6450
|
+
this.applyViewModeFromRoute()
|
|
6451
|
+
},
|
|
6452
|
+
|
|
6453
|
+
boardFetchKey: {
|
|
6454
|
+
immediate: true,
|
|
6455
|
+
handler(key) {
|
|
6456
|
+
if (key !== '') {
|
|
6457
|
+
this.loadBoardSources()
|
|
6458
|
+
}
|
|
6459
|
+
},
|
|
6460
|
+
},
|
|
6461
|
+
|
|
6048
6462
|
effectiveObjects: {
|
|
6049
6463
|
immediate: true,
|
|
6050
6464
|
handler(rows) {
|
|
@@ -6118,22 +6532,33 @@ export default {
|
|
|
6118
6532
|
// Entering calendar mode fetches one page sized to the month; leaving
|
|
6119
6533
|
// removes the month range and restores the page size, so the table is
|
|
6120
6534
|
// never left narrowed.
|
|
6535
|
+
// The board does the same at BOARD_PAGE_SIZE, so it shows every row
|
|
6536
|
+
// rather than the table's first page.
|
|
6121
6537
|
currentViewMode(mode, previous) {
|
|
6122
6538
|
if (!this.isSelfFetchMode) {
|
|
6123
6539
|
return
|
|
6124
6540
|
}
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
if (typeof this.list.onPageSizeChange === 'function') {
|
|
6128
|
-
this.list.onPageSizeChange(CALENDAR_PAGE_SIZE)
|
|
6129
|
-
}
|
|
6130
|
-
} else if (previous === 'calendar') {
|
|
6541
|
+
let listSize = this.list.pageSize.value
|
|
6542
|
+
if (previous === 'calendar') {
|
|
6131
6543
|
this.calendarRange = null
|
|
6132
|
-
|
|
6544
|
+
listSize = this.calendarPrevPageSize || 20
|
|
6133
6545
|
this.calendarPrevPageSize = null
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6546
|
+
} else if (previous === 'board') {
|
|
6547
|
+
listSize = this.boardPrevPageSize || 20
|
|
6548
|
+
this.boardPrevPageSize = null
|
|
6549
|
+
}
|
|
6550
|
+
let size = null
|
|
6551
|
+
if (mode === 'calendar') {
|
|
6552
|
+
this.calendarPrevPageSize = listSize
|
|
6553
|
+
size = CALENDAR_PAGE_SIZE
|
|
6554
|
+
} else if (mode === 'board') {
|
|
6555
|
+
this.boardPrevPageSize = listSize
|
|
6556
|
+
size = BOARD_PAGE_SIZE
|
|
6557
|
+
} else if (previous === 'calendar' || previous === 'board') {
|
|
6558
|
+
size = listSize
|
|
6559
|
+
}
|
|
6560
|
+
if (size !== null && typeof this.list.onPageSizeChange === 'function') {
|
|
6561
|
+
this.list.onPageSizeChange(size)
|
|
6137
6562
|
}
|
|
6138
6563
|
},
|
|
6139
6564
|
|
|
@@ -6288,6 +6713,7 @@ export default {
|
|
|
6288
6713
|
},
|
|
6289
6714
|
|
|
6290
6715
|
created() {
|
|
6716
|
+
this.applyViewModeFromRoute()
|
|
6291
6717
|
this.pushAiContext()
|
|
6292
6718
|
if (this.allowSavedViews) {
|
|
6293
6719
|
this.fetchSavedViews()
|
|
@@ -7070,6 +7496,11 @@ export default {
|
|
|
7070
7496
|
const entry = this.mergedHeaderActions.find((e) => e.id === id)
|
|
7071
7497
|
if (entry && typeof entry.handler === 'function') {
|
|
7072
7498
|
entry.handler()
|
|
7499
|
+
} else {
|
|
7500
|
+
const dialogRun = this.dialogHeaderRuns.find((e) => e.id === id)
|
|
7501
|
+
if (dialogRun && typeof dialogRun.run === 'function') {
|
|
7502
|
+
dialogRun.run()
|
|
7503
|
+
}
|
|
7073
7504
|
}
|
|
7074
7505
|
if (entry && entry._dispatchSuppress) {
|
|
7075
7506
|
return
|
|
@@ -7077,6 +7508,49 @@ export default {
|
|
|
7077
7508
|
this.$emit('header-action', { action: id, id })
|
|
7078
7509
|
},
|
|
7079
7510
|
|
|
7511
|
+
/**
|
|
7512
|
+
* The `countSubtitle` line for a total. A string goes through the host
|
|
7513
|
+
* translate; `{ singular, plural }` takes the form for the total
|
|
7514
|
+
* through the app's plural translation, or by `total === 1` when no app
|
|
7515
|
+
* id is provided. `{total}` (and `{shown}` when given) are filled in.
|
|
7516
|
+
*
|
|
7517
|
+
* @spec openspec/changes/index-count-plural/specs/index-header/spec.md#requirement-the-count-line-takes-a-singular-and-a-plural-form
|
|
7518
|
+
* @param {string|{singular: string, plural: string}} subtitle The declared line.
|
|
7519
|
+
* @param {number} total The collection's total.
|
|
7520
|
+
* @param {number|null} shown The rows on this page, or null to leave `{shown}` alone.
|
|
7521
|
+
* @return {string} The line, '' for a declaration without both forms.
|
|
7522
|
+
*/
|
|
7523
|
+
countLine(subtitle, total, shown) {
|
|
7524
|
+
const fill = (text) => {
|
|
7525
|
+
const out = String(text).replace('{total}', String(total))
|
|
7526
|
+
return shown === null ? out : out.replace('{shown}', String(shown))
|
|
7527
|
+
}
|
|
7528
|
+
if (typeof subtitle === 'string') {
|
|
7529
|
+
return fill(this.cnTranslate(subtitle))
|
|
7530
|
+
}
|
|
7531
|
+
const singular = subtitle && typeof subtitle.singular === 'string' ? subtitle.singular : ''
|
|
7532
|
+
const plural = subtitle && typeof subtitle.plural === 'string' ? subtitle.plural : ''
|
|
7533
|
+
if (singular === '' || plural === '') {
|
|
7534
|
+
return ''
|
|
7535
|
+
}
|
|
7536
|
+
if (typeof this.cnAppId === 'string' && this.cnAppId !== '') {
|
|
7537
|
+
const vars = shown === null ? { total } : { total, shown }
|
|
7538
|
+
return n(this.cnAppId, singular, plural, total, vars)
|
|
7539
|
+
}
|
|
7540
|
+
return fill(this.cnTranslate(total === 1 ? singular : plural))
|
|
7541
|
+
},
|
|
7542
|
+
|
|
7543
|
+
/**
|
|
7544
|
+
* An `open-form` header action saved a record: the list reloads so the
|
|
7545
|
+
* new row shows.
|
|
7546
|
+
*
|
|
7547
|
+
* @spec openspec/changes/index-header-open-form/specs/index-header/spec.md#requirement-an-index-header-action-can-open-the-create-form
|
|
7548
|
+
* @return {void}
|
|
7549
|
+
*/
|
|
7550
|
+
onHeaderActionCreated() {
|
|
7551
|
+
this.onRefreshEvent()
|
|
7552
|
+
},
|
|
7553
|
+
|
|
7080
7554
|
pushAiContext() {
|
|
7081
7555
|
applyAiContext(this.cnAiContext, 'index', {
|
|
7082
7556
|
register: this.register,
|
|
@@ -7292,6 +7766,72 @@ export default {
|
|
|
7292
7766
|
this.$emit('clear-filters')
|
|
7293
7767
|
},
|
|
7294
7768
|
|
|
7769
|
+
/**
|
|
7770
|
+
* Fetch what the board view needs: the rows of a reference column
|
|
7771
|
+
* field (once per field) and the narrowing select's options.
|
|
7772
|
+
*
|
|
7773
|
+
* @return {Promise<void>}
|
|
7774
|
+
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references
|
|
7775
|
+
*/
|
|
7776
|
+
async loadBoardSources() {
|
|
7777
|
+
const active = this.boardActiveColumnField
|
|
7778
|
+
if (active && active.kind === 'reference' && !Object.hasOwn(this.boardRefs, active.field)) {
|
|
7779
|
+
const property = this.effectiveSchema?.properties?.[active.field] || null
|
|
7780
|
+
const target = referenceTargetOf(active.source, { register: this.register, property })
|
|
7781
|
+
if (target.register && target.schema) {
|
|
7782
|
+
let rows
|
|
7783
|
+
try {
|
|
7784
|
+
rows = await fetchReferenceObjects({ ...target, filter: active.source?.filter || {} })
|
|
7785
|
+
} catch {
|
|
7786
|
+
rows = []
|
|
7787
|
+
}
|
|
7788
|
+
this.boardRefs = { ...this.boardRefs, [active.field]: rows }
|
|
7789
|
+
}
|
|
7790
|
+
}
|
|
7791
|
+
const narrow = this.boardNarrow
|
|
7792
|
+
if (narrow && this.boardNarrowOptions.length === 0) {
|
|
7793
|
+
const property = this.effectiveSchema?.properties?.[narrow.field] || null
|
|
7794
|
+
const target = referenceTargetOf(narrow.source || {}, { register: this.register, property })
|
|
7795
|
+
let rows
|
|
7796
|
+
try {
|
|
7797
|
+
rows = await fetchReferenceObjects({ ...target, filter: narrow.source?.filter || {} })
|
|
7798
|
+
} catch {
|
|
7799
|
+
rows = []
|
|
7800
|
+
}
|
|
7801
|
+
const labelField = narrow.source?.labelField || 'title'
|
|
7802
|
+
this.boardNarrowOptions = rows
|
|
7803
|
+
.map((row) => ({ value: refIdOf(row), label: String(row?.[labelField] ?? row?.name ?? row?.title ?? refIdOf(row)) }))
|
|
7804
|
+
.filter((option) => option.value !== '')
|
|
7805
|
+
.sort((a, b) => a.label.localeCompare(b.label))
|
|
7806
|
+
}
|
|
7807
|
+
},
|
|
7808
|
+
|
|
7809
|
+
/**
|
|
7810
|
+
* The column switch changed.
|
|
7811
|
+
*
|
|
7812
|
+
* @param {string} field The column field picked.
|
|
7813
|
+
* @return {void}
|
|
7814
|
+
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-board-can-switch-the-field-its-columns-come-from
|
|
7815
|
+
*/
|
|
7816
|
+
onBoardColumnFieldChange(field) {
|
|
7817
|
+
this.boardColumnFieldChoice = field
|
|
7818
|
+
/**
|
|
7819
|
+
* @event board-column-field-change The board's column switch picked another field. Payload: the field name.
|
|
7820
|
+
*/
|
|
7821
|
+
this.$emit('board-column-field-change', field)
|
|
7822
|
+
},
|
|
7823
|
+
|
|
7824
|
+
/**
|
|
7825
|
+
* The narrowing select changed: it sets the page filter on its field,
|
|
7826
|
+
* so the cards narrow with the columns and the active filter shows.
|
|
7827
|
+
*
|
|
7828
|
+
* @param {string} value The parent id, '' for all.
|
|
7829
|
+
* @return {void}
|
|
7830
|
+
*/
|
|
7831
|
+
onBoardNarrowChange(value) {
|
|
7832
|
+
this.onFilterEvent({ key: this.boardNarrow.field, values: value === '' ? [] : [value] })
|
|
7833
|
+
},
|
|
7834
|
+
|
|
7295
7835
|
/**
|
|
7296
7836
|
* A paged board's "Show N more": ask for the next page.
|
|
7297
7837
|
*
|
|
@@ -7299,6 +7839,10 @@ export default {
|
|
|
7299
7839
|
* @spec openspec/changes/screens-kanban-parity/specs/board-view/spec.md#requirement-a-long-column-is-cut-with-a-show-more-button
|
|
7300
7840
|
*/
|
|
7301
7841
|
onBoardLoadMore() {
|
|
7842
|
+
if (this.boardLoadsAll) {
|
|
7843
|
+
this.list.loadMore()
|
|
7844
|
+
return
|
|
7845
|
+
}
|
|
7302
7846
|
const page = Number(this.pagination?.page || 1)
|
|
7303
7847
|
if (page < Number(this.pagination?.pages || 1)) {
|
|
7304
7848
|
this.onPageEvent(page + 1)
|
|
@@ -8637,6 +9181,23 @@ export default {
|
|
|
8637
9181
|
this.$emit('view-mode-change', mode)
|
|
8638
9182
|
},
|
|
8639
9183
|
|
|
9184
|
+
/**
|
|
9185
|
+
* Open in the mode the address names (`?_view=board`), when the page
|
|
9186
|
+
* offers it. The key starts with `_`, like `_search` and `_page`, so it
|
|
9187
|
+
* is never read as a list filter. A menu entry's `query` can so open a
|
|
9188
|
+
* list as its board, on the one page that lists the schema
|
|
9189
|
+
* (screens-board-reference-columns).
|
|
9190
|
+
*
|
|
9191
|
+
* @return {void}
|
|
9192
|
+
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-the-address-can-open-a-list-in-a-view-mode
|
|
9193
|
+
*/
|
|
9194
|
+
applyViewModeFromRoute() {
|
|
9195
|
+
const wanted = this.$route?.query?._view
|
|
9196
|
+
if (typeof wanted === 'string' && wanted !== this.currentViewMode && this.effectiveToggleModes.includes(wanted)) {
|
|
9197
|
+
this.currentViewMode = wanted
|
|
9198
|
+
}
|
|
9199
|
+
},
|
|
9200
|
+
|
|
8640
9201
|
/**
|
|
8641
9202
|
* Handle selection changes from CnDataTable/CnCardGrid.
|
|
8642
9203
|
* Updates internal state and re-emits for parent.
|