@conduction/nextcloud-vue 2.96.0 → 2.98.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/CnAppRoot/CnAppRoot.vue2.js +17 -0
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +383 -359
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +106 -2
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js +9 -0
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js.map +1 -0
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js +964 -0
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js +282 -0
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnChecklistRunWidget/index.js +28 -0
- package/dist/esm/components/CnChecklistRunWidget/index.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +17 -3
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +61 -43
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +159 -18
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +9 -7
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +1 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +26 -8
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +188 -5
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +48 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +46 -12
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +3 -3
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +27 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +16 -2
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +144 -0
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +488 -399
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +8 -2
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +344 -21
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +29 -7
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +2 -2
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +2 -2
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js +1 -1
- package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +13 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +5 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +9 -0
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js.map +1 -0
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +220 -0
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -0
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +121 -0
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -0
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js +83 -9
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js +80 -11
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/composables/indexSources.js +420 -5
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/composables/useOrganisationStore.js +115 -0
- package/dist/esm/composables/useOrganisationStore.js.map +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +21 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +36 -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 +725 -383
- package/dist/esm/utils/builtInFormatters.js +34 -1
- package/dist/esm/utils/builtInFormatters.js.map +1 -1
- package/dist/esm/utils/libraryWidgetKeys.js +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/matrixCells.js +158 -0
- package/dist/esm/utils/matrixCells.js.map +1 -0
- package/dist/esm/utils/nextcloudDirectory.js +121 -0
- package/dist/esm/utils/nextcloudDirectory.js.map +1 -0
- package/dist/esm/utils/queryPresets.js +13 -2
- package/dist/esm/utils/queryPresets.js.map +1 -1
- package/dist/esm/utils/scopeListLayout.js +37 -1
- package/dist/esm/utils/scopeListLayout.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/nextcloud-vue.cjs.js +14443 -10519
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +725 -383
- package/l10n/en.json +21 -1
- package/l10n/nl.json +36 -1
- package/package.json +2 -2
- package/scripts/merge-l10n.js +196 -0
- package/src/components/CnAppRoot/CnAppRoot.md +1 -0
- package/src/components/CnAppRoot/CnAppRoot.vue +17 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +57 -1
- package/src/components/CnChartWidget/CnChartWidget.md +2 -1
- package/src/components/CnChartWidget/CnChartWidget.vue +106 -2
- package/src/components/CnChecklistRunWidget/CnChecklistRunWidget.vue +1269 -0
- package/src/components/CnChecklistRunWidget/index.js +27 -0
- package/src/components/CnConversationThread/CnConversationThread.md +12 -0
- package/src/components/CnConversationThread/CnConversationThread.vue +30 -4
- package/src/components/CnConversationThread/CnConversationWidget.vue +167 -24
- package/src/components/CnDashboardPage/CnDashboardPage.vue +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +26 -8
- package/src/components/CnDetailPage/CnDetailPage.md +48 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +188 -5
- package/src/components/CnFactsWidget/CnFactsWidget.vue +114 -3
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +3 -3
- package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +38 -2
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +508 -236
- package/src/components/CnFilesBrowser/filesBrowserColumns.js +8 -2
- package/src/components/CnIndexPage/CnIndexPage.md +28 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +367 -27
- package/src/components/CnIndexPage/CnIndexPageWidgets.vue +13 -4
- package/src/components/CnIndexPage/useNamedSource.js +1 -1
- package/src/components/CnObjectSidebar/CnFilesTab.vue +17 -0
- package/src/components/CnOrderedListField/CnOrderedListField.vue +386 -0
- package/src/components/CnOrderedListField/index.js +7 -0
- package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +139 -10
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/src/components/index.js +2 -0
- package/src/composables/indexSources.js +419 -4
- package/src/composables/useOrganisationStore.js +111 -0
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +42 -5
- package/src/utils/builtInFormatters.js +33 -0
- package/src/utils/libraryWidgetKeys.js +1 -0
- package/src/utils/matrixCells.js +154 -0
- package/src/utils/nextcloudDirectory.js +117 -0
- package/src/utils/queryPresets.js +13 -2
- package/src/utils/scopeListLayout.js +37 -1
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
region (WCAG 2.4.6 / 1.3.1). -->
|
|
14
14
|
<slot
|
|
15
15
|
name="header"
|
|
16
|
-
:title="title"
|
|
16
|
+
:title="presented('title')"
|
|
17
17
|
:description="headerDescription"
|
|
18
18
|
:icon="resolvedIcon"
|
|
19
19
|
:showTitle="showTitle">
|
|
20
20
|
<CnPageHeader
|
|
21
|
-
:title="title"
|
|
21
|
+
:title="presented('title')"
|
|
22
22
|
:description="headerDescription"
|
|
23
23
|
:icon="showTitleIcon && !isBoardLook ? resolvedIcon : ''"
|
|
24
|
-
:breadcrumb="breadcrumb"
|
|
24
|
+
:breadcrumb="presented('breadcrumb')"
|
|
25
25
|
:meta="headerMetaText"
|
|
26
26
|
:visuallyHidden="!showTitle">
|
|
27
27
|
<!-- The board's header buttons (`headerButtons`), beside the
|
|
@@ -125,11 +125,11 @@
|
|
|
125
125
|
<!-- Page tabs a named source declares (`pageTabs()`): sibling lists
|
|
126
126
|
of the same thing, such as a flow list and its runs this week.
|
|
127
127
|
Links, not tabs: each one is its own page. -->
|
|
128
|
-
<nav v-if="
|
|
128
|
+
<nav v-if="effectivePageTabs.length > 0"
|
|
129
129
|
class="cn-index-page__page-tabs"
|
|
130
130
|
:aria-label="title || t('nextcloud-vue', 'Pages')"
|
|
131
131
|
data-testid="cn-index-page-tabs">
|
|
132
|
-
<a v-for="tab in
|
|
132
|
+
<a v-for="tab in effectivePageTabs"
|
|
133
133
|
:key="tab.id || tab.to"
|
|
134
134
|
class="cn-index-page__page-tab"
|
|
135
135
|
:class="{ 'cn-index-page__page-tab--active': isActivePageTab(tab) }"
|
|
@@ -193,7 +193,7 @@
|
|
|
193
193
|
:sortValue="sortSelectValue"
|
|
194
194
|
:showSearch="inlineSearch || isBoardLook"
|
|
195
195
|
:searchValue="effectiveSearchValue"
|
|
196
|
-
:searchPlaceholder="searchPlaceholder ? cnTranslate(searchPlaceholder) : searchPlaceholder"
|
|
196
|
+
:searchPlaceholder="presented('searchPlaceholder') ? cnTranslate(presented('searchPlaceholder')) : presented('searchPlaceholder')"
|
|
197
197
|
:showCountWithSearch="showCountWithSearch"
|
|
198
198
|
:refreshing="effectiveRefreshing"
|
|
199
199
|
:refreshDisabled="refreshDisabled"
|
|
@@ -1075,6 +1075,23 @@
|
|
|
1075
1075
|
class="cn-index-page__pagination"
|
|
1076
1076
|
@pageChanged="onPageEvent"
|
|
1077
1077
|
@pageSizeChanged="onPageSizeEvent" />
|
|
1078
|
+
|
|
1079
|
+
<!-- A notice under the list (`notice`): DqPrivacy's "Een
|
|
1080
|
+
AVG-verzoek is een zaak met ..." band. -->
|
|
1081
|
+
<NcNoteCard
|
|
1082
|
+
v-if="notice && notice.text"
|
|
1083
|
+
class="cn-index-page__notice"
|
|
1084
|
+
:type="noticeType"
|
|
1085
|
+
data-testid="cn-index-page-notice">
|
|
1086
|
+
{{ cnTranslate(notice.text) }}
|
|
1087
|
+
</NcNoteCard>
|
|
1088
|
+
|
|
1089
|
+
<!-- Cards after the list (`afterList`), stacked in order (PqSocial). -->
|
|
1090
|
+
<CnIndexPageWidgets
|
|
1091
|
+
v-if="presentedAfterList.length > 0"
|
|
1092
|
+
class="cn-index-page__after-list"
|
|
1093
|
+
variant="after-list"
|
|
1094
|
+
:widgets="presentedAfterList" />
|
|
1078
1095
|
</div>
|
|
1079
1096
|
|
|
1080
1097
|
<!-- The open record, beside the list on a wide screen and instead
|
|
@@ -1158,7 +1175,7 @@
|
|
|
1158
1175
|
<script>
|
|
1159
1176
|
import { getCurrentUser } from '@nextcloud/auth'
|
|
1160
1177
|
import { translatePlural as n, translate as t } from '@nextcloud/l10n'
|
|
1161
|
-
import { NcActionButton, NcActionCaption, NcActionCheckbox, NcActionLink, NcActions, NcActionSeparator, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'
|
|
1178
|
+
import { NcActionButton, NcActionCaption, NcActionCheckbox, NcActionLink, NcActions, NcActionSeparator, NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'
|
|
1162
1179
|
import { getCurrentInstance, inject, markRaw, ref } from 'vue'
|
|
1163
1180
|
import AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'
|
|
1164
1181
|
import Close from 'vue-material-design-icons/Close.vue'
|
|
@@ -1200,13 +1217,14 @@ import {
|
|
|
1200
1217
|
} from '../../utils/boardReferenceColumns.js'
|
|
1201
1218
|
import { reportBindingProblems } from '../../utils/diagnostics.js'
|
|
1202
1219
|
import { fetchGroupedCounts } from '../../utils/fetchAggregate.js'
|
|
1203
|
-
import { fetchFilterCounts } from '../../utils/fetchFilterCounts.js'
|
|
1220
|
+
import { fetchFilterCounts, fetchListTotal } from '../../utils/fetchFilterCounts.js'
|
|
1204
1221
|
import { buildExportUrl } from '../../utils/indexExportHelpers.js'
|
|
1205
1222
|
import { lensUnavailableText } from '../../utils/lensAvailability.js'
|
|
1206
1223
|
import { isModifiedClick, openRowTarget } from '../../utils/linkNavigation.js'
|
|
1207
1224
|
import { resolveClaimedTeams, resolveClaimTokens, splitViewsIntoTabs, viewAsTab, viewIdOf } from '../../utils/listLenses.js'
|
|
1208
1225
|
import { LIST_SHORTCUTS, listPaletteCommands, shortcutFor } from '../../utils/listShortcuts.js'
|
|
1209
1226
|
import { multiKeySort } from '../../utils/multiKeySort.js'
|
|
1227
|
+
import { fetchGroups } from '../../utils/nextcloudDirectory.js'
|
|
1210
1228
|
import { OBJECTS_CHANGED_EVENT } from '../../utils/objectSignals.js'
|
|
1211
1229
|
import { objectUrlOf, patchObject } from '../../utils/objectWrite.js'
|
|
1212
1230
|
import { withPersonalLenses } from '../../utils/personalLenses.js'
|
|
@@ -1219,7 +1237,7 @@ import { isNewTabClick, isNewTabHandled, isRowMiddleClick, markNewTabHandled, pr
|
|
|
1219
1237
|
import { DEFAULT_ROW_INDICATOR_CAP } from '../../utils/rowIndicators.js'
|
|
1220
1238
|
import { buildRouteQueryFromViewState, buildViewCreatePayload, extractViewState, extractViewStateFromRouteQuery, normalizeSharedWith, savedViewScope, viewMatchesScope } from '../../utils/savedViewHelpers.js'
|
|
1221
1239
|
import { columnsFromSchema, fieldsFromSchema } from '../../utils/schema.js'
|
|
1222
|
-
import { resolveScopeLayout } from '../../utils/scopeListLayout.js'
|
|
1240
|
+
import { resolveScopeLayout, resolveScopePresentation } from '../../utils/scopeListLayout.js'
|
|
1223
1241
|
import { dispatchObjectCreated } from '../../utils/walkthroughSignals.js'
|
|
1224
1242
|
import { CnActionButtons } from '../CnActionButtons/index.js'
|
|
1225
1243
|
import { CnActionsBar } from '../CnActionsBar/index.js'
|
|
@@ -1490,6 +1508,7 @@ export default {
|
|
|
1490
1508
|
|
|
1491
1509
|
components: {
|
|
1492
1510
|
CnIndexPageWidgets,
|
|
1511
|
+
NcNoteCard,
|
|
1493
1512
|
CnBuildiqEditButton,
|
|
1494
1513
|
CnFollowToggle,
|
|
1495
1514
|
NcLoadingIcon,
|
|
@@ -1658,6 +1677,35 @@ export default {
|
|
|
1658
1677
|
default: '',
|
|
1659
1678
|
},
|
|
1660
1679
|
|
|
1680
|
+
/**
|
|
1681
|
+
* Tabs to sibling pages above the toolbar (manifest `config.pageTabs`),
|
|
1682
|
+
* each `{ id?, label, route?, params?, query?, href?, countFrom?: {
|
|
1683
|
+
* register, schema, filter? } }`: DqPrivacy's "AVG-verzoeken |
|
|
1684
|
+
* Datalekken". The current page's tab is marked; `countFrom` adds the
|
|
1685
|
+
* count of that list. Wins over a named source's own page tabs.
|
|
1686
|
+
*
|
|
1687
|
+
* @type {Array<object>|null}
|
|
1688
|
+
* @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-link-its-sibling-pages-as-tabs
|
|
1689
|
+
*/
|
|
1690
|
+
pageTabs: {
|
|
1691
|
+
type: Array,
|
|
1692
|
+
default: null,
|
|
1693
|
+
},
|
|
1694
|
+
|
|
1695
|
+
/**
|
|
1696
|
+
* A notice under the list (manifest `config.notice`): `{ text,
|
|
1697
|
+
* variant?: 'info' | 'success' | 'warning' }`, a band that explains
|
|
1698
|
+
* the list, such as who decides what. The text goes through the host
|
|
1699
|
+
* translate.
|
|
1700
|
+
*
|
|
1701
|
+
* @type {{text: string, variant?: string}|null}
|
|
1702
|
+
* @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-show-a-notice-under-its-list
|
|
1703
|
+
*/
|
|
1704
|
+
notice: {
|
|
1705
|
+
type: Object,
|
|
1706
|
+
default: null,
|
|
1707
|
+
},
|
|
1708
|
+
|
|
1661
1709
|
/** Optional description shown below the title */
|
|
1662
1710
|
description: {
|
|
1663
1711
|
type: String,
|
|
@@ -3045,6 +3093,33 @@ export default {
|
|
|
3045
3093
|
default: () => [],
|
|
3046
3094
|
},
|
|
3047
3095
|
|
|
3096
|
+
/**
|
|
3097
|
+
* Cards after the list (manifest `config.afterList`): dashboard widget
|
|
3098
|
+
* definitions `{ id, type, title?, content, headerLink? }` stacked
|
|
3099
|
+
* under the list in the listed order, the counterpart of `statRow`
|
|
3100
|
+
* above it. A query preset or a scope can set its own.
|
|
3101
|
+
*
|
|
3102
|
+
* @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-an-index-page-can-draw-widgets-after-its-list
|
|
3103
|
+
* @type {Array<object>}
|
|
3104
|
+
*/
|
|
3105
|
+
afterList: {
|
|
3106
|
+
type: Array,
|
|
3107
|
+
default: () => [],
|
|
3108
|
+
},
|
|
3109
|
+
|
|
3110
|
+
/**
|
|
3111
|
+
* The route query pairs that chose this page's query preset, set by
|
|
3112
|
+
* CnPageRenderer. They scope the list, so they show no removable
|
|
3113
|
+
* active-filter chip.
|
|
3114
|
+
*
|
|
3115
|
+
* @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-the-query-that-chose-a-preset-is-not-a-removable-filter
|
|
3116
|
+
* @type {object|null}
|
|
3117
|
+
*/
|
|
3118
|
+
fixedFilters: {
|
|
3119
|
+
type: Object,
|
|
3120
|
+
default: null,
|
|
3121
|
+
},
|
|
3122
|
+
|
|
3048
3123
|
/**
|
|
3049
3124
|
* Where a row carries the actions the server says this caller may run
|
|
3050
3125
|
* on it: a dotted path, read off the rows the list already fetched, so
|
|
@@ -3645,6 +3720,8 @@ export default {
|
|
|
3645
3720
|
tabCounts: null,
|
|
3646
3721
|
// The counts of the `filterStrip` pills, by pill key ('all', 'v0', ...).
|
|
3647
3722
|
filterStripCounts: null,
|
|
3723
|
+
/** The `countFrom` counts of the manifest page tabs, by index. */
|
|
3724
|
+
pageTabCounts: {},
|
|
3648
3725
|
/** The tabs `quickFiltersFrom` produced, or null before they load. */
|
|
3649
3726
|
generatedQuickFilters: null,
|
|
3650
3727
|
/** Count per saved-view id, for the views control; null = none. */
|
|
@@ -3673,6 +3750,8 @@ export default {
|
|
|
3673
3750
|
*/
|
|
3674
3751
|
folderSidebarAllValues: [],
|
|
3675
3752
|
folderRegisterList: [],
|
|
3753
|
+
/** The Nextcloud groups a `folderSidebar.source: 'groups'` pane lists. */
|
|
3754
|
+
folderGroupList: [],
|
|
3676
3755
|
// `x-index` blocks read off the schema rows a `source: 'register'`
|
|
3677
3756
|
// folder list was built from, keyed by folder id. The layout a case
|
|
3678
3757
|
// type carries travels with the record rather than being restated
|
|
@@ -4194,7 +4273,8 @@ export default {
|
|
|
4194
4273
|
}
|
|
4195
4274
|
// The index boards draw all four segments, so the board look does
|
|
4196
4275
|
// too unless the manifest names its own list.
|
|
4197
|
-
const
|
|
4276
|
+
const viewSwitch = this.presented('viewSwitch')
|
|
4277
|
+
const listed = Array.isArray(viewSwitch) ? viewSwitch : ['table', 'cards', 'board', 'map']
|
|
4198
4278
|
const offered = [...this.effectiveToggleModes, ...(this.showMapSegment ? ['map'] : [])]
|
|
4199
4279
|
return listed.filter((mode) => ['table', 'cards', 'board', 'map'].includes(mode) && !offered.includes(mode))
|
|
4200
4280
|
},
|
|
@@ -4589,7 +4669,7 @@ export default {
|
|
|
4589
4669
|
*/
|
|
4590
4670
|
folderSidebarSource() {
|
|
4591
4671
|
const s = this.folderSidebar && this.folderSidebar.source
|
|
4592
|
-
return (s === 'register' || !s) ? 'custom' : s
|
|
4672
|
+
return (s === 'register' || s === 'groups' || !s) ? 'custom' : s
|
|
4593
4673
|
},
|
|
4594
4674
|
|
|
4595
4675
|
/**
|
|
@@ -4606,6 +4686,9 @@ export default {
|
|
|
4606
4686
|
if (this.folderSidebar.source === 'register') {
|
|
4607
4687
|
return this.folderRegisterList
|
|
4608
4688
|
}
|
|
4689
|
+
if (this.folderSidebar.source === 'groups') {
|
|
4690
|
+
return this.folderGroupList
|
|
4691
|
+
}
|
|
4609
4692
|
return this.folderSidebar.folders || []
|
|
4610
4693
|
},
|
|
4611
4694
|
|
|
@@ -4665,6 +4748,58 @@ export default {
|
|
|
4665
4748
|
})
|
|
4666
4749
|
},
|
|
4667
4750
|
|
|
4751
|
+
/**
|
|
4752
|
+
* This page's own value of each presentation key, which a query preset
|
|
4753
|
+
* may have set: what `presented()` falls back to without a scope.
|
|
4754
|
+
*
|
|
4755
|
+
* @return {object}
|
|
4756
|
+
* @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-a-preset-or-a-scope-sets-the-list-s-presentation
|
|
4757
|
+
*/
|
|
4758
|
+
ownPresentation() {
|
|
4759
|
+
return {
|
|
4760
|
+
title: this.title,
|
|
4761
|
+
quickFilters: this.quickFilters,
|
|
4762
|
+
cardFields: this.cardFields,
|
|
4763
|
+
countText: this.countText,
|
|
4764
|
+
searchPlaceholder: this.searchPlaceholder,
|
|
4765
|
+
footerNote: this.footerNote,
|
|
4766
|
+
viewSwitch: this.viewSwitch,
|
|
4767
|
+
addLabel: this.addLabel,
|
|
4768
|
+
headerButtons: this.headerButtons,
|
|
4769
|
+
breadcrumb: this.breadcrumb,
|
|
4770
|
+
headerMeta: this.headerMeta,
|
|
4771
|
+
afterList: this.afterList,
|
|
4772
|
+
}
|
|
4773
|
+
},
|
|
4774
|
+
|
|
4775
|
+
/**
|
|
4776
|
+
* The presentation the active scope declares (`title`, `countText`,
|
|
4777
|
+
* `quickFilters`, `addLabel`, `afterList` and the other query preset
|
|
4778
|
+
* keys), from its folder entry or its row's `x-index`. Empty without a
|
|
4779
|
+
* scope, so the page's own values stand.
|
|
4780
|
+
*
|
|
4781
|
+
* @return {object}
|
|
4782
|
+
* @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-a-preset-or-a-scope-sets-the-list-s-presentation
|
|
4783
|
+
*/
|
|
4784
|
+
activeScopePresentation() {
|
|
4785
|
+
if (!this.folderSidebar) {
|
|
4786
|
+
return {}
|
|
4787
|
+
}
|
|
4788
|
+
return resolveScopePresentation({ scope: this.activeScope, row: this.activeScopeRow })
|
|
4789
|
+
},
|
|
4790
|
+
|
|
4791
|
+
/**
|
|
4792
|
+
* The widgets drawn after the list: the active scope's `afterList`,
|
|
4793
|
+
* else the page's.
|
|
4794
|
+
*
|
|
4795
|
+
* @return {Array<object>}
|
|
4796
|
+
* @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-an-index-page-can-draw-widgets-after-its-list
|
|
4797
|
+
*/
|
|
4798
|
+
presentedAfterList() {
|
|
4799
|
+
const list = this.presented('afterList')
|
|
4800
|
+
return Array.isArray(list) ? list : []
|
|
4801
|
+
},
|
|
4802
|
+
|
|
4668
4803
|
/**
|
|
4669
4804
|
* The fields the search box searches over while a scope declaring
|
|
4670
4805
|
* `searchFields` is active. Read by `useSelfFetchList`'s fixed-filter
|
|
@@ -5124,8 +5259,9 @@ export default {
|
|
|
5124
5259
|
* @return {?Array<string>}
|
|
5125
5260
|
*/
|
|
5126
5261
|
resolvedCardFields() {
|
|
5127
|
-
|
|
5128
|
-
|
|
5262
|
+
const cardFields = this.presented('cardFields')
|
|
5263
|
+
if (Array.isArray(cardFields) && cardFields.length > 0) {
|
|
5264
|
+
return cardFields
|
|
5129
5265
|
}
|
|
5130
5266
|
if (!this.isBoardLook) {
|
|
5131
5267
|
return null
|
|
@@ -5164,6 +5300,10 @@ export default {
|
|
|
5164
5300
|
}
|
|
5165
5301
|
})
|
|
5166
5302
|
}
|
|
5303
|
+
// An `actions` column: the page's row actions it names, as buttons.
|
|
5304
|
+
cols = cols.map((col) => (col && typeof col === 'object' && col.widget === 'actions'
|
|
5305
|
+
? { ...col, sortable: false, widgetProps: { ...(col.widgetProps || {}), items: (row) => this.actionColumnItems(col, row), run: this.runColumnAction } }
|
|
5306
|
+
: col))
|
|
5167
5307
|
// The Recent lens owns the order: no column sorts while it is on.
|
|
5168
5308
|
if (this.recentLensActive) {
|
|
5169
5309
|
cols = cols.map((col) => (col && typeof col === 'object' ? { ...col, sortable: false } : col))
|
|
@@ -5314,7 +5454,7 @@ export default {
|
|
|
5314
5454
|
* @return {string} The id field key.
|
|
5315
5455
|
*/
|
|
5316
5456
|
folderPassthroughIdField() {
|
|
5317
|
-
if (this.folderSidebar && this.folderSidebar.source === 'register') {
|
|
5457
|
+
if (this.folderSidebar && (this.folderSidebar.source === 'register' || this.folderSidebar.source === 'groups')) {
|
|
5318
5458
|
return 'id'
|
|
5319
5459
|
}
|
|
5320
5460
|
return (this.folderSidebar && this.folderSidebar.idField) || 'id'
|
|
@@ -5324,7 +5464,7 @@ export default {
|
|
|
5324
5464
|
* @return {string} The name field key for CnFolderSidebar's custom list.
|
|
5325
5465
|
*/
|
|
5326
5466
|
folderPassthroughNameField() {
|
|
5327
|
-
if (this.folderSidebar && this.folderSidebar.source === 'register') {
|
|
5467
|
+
if (this.folderSidebar && (this.folderSidebar.source === 'register' || this.folderSidebar.source === 'groups')) {
|
|
5328
5468
|
return 'name'
|
|
5329
5469
|
}
|
|
5330
5470
|
return (this.folderSidebar && this.folderSidebar.nameField) || 'name'
|
|
@@ -6040,6 +6180,51 @@ export default {
|
|
|
6040
6180
|
return (source.pageTabs() || []).filter((tab) => tab && tab.to && tab.label)
|
|
6041
6181
|
},
|
|
6042
6182
|
|
|
6183
|
+
/**
|
|
6184
|
+
* The page tabs to draw: the manifest's `pageTabs`, each with its
|
|
6185
|
+
* `countFrom` count once known, else a named source's own.
|
|
6186
|
+
*
|
|
6187
|
+
* @return {Array<object>} The tabs, `{ id, label, to, count? }`.
|
|
6188
|
+
* @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-link-its-sibling-pages-as-tabs
|
|
6189
|
+
*/
|
|
6190
|
+
/**
|
|
6191
|
+
* The notice band's NcNoteCard type: its `variant`, else info.
|
|
6192
|
+
*
|
|
6193
|
+
* @return {string}
|
|
6194
|
+
* @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-show-a-notice-under-its-list
|
|
6195
|
+
*/
|
|
6196
|
+
noticeType() {
|
|
6197
|
+
const variant = this.notice && this.notice.variant
|
|
6198
|
+
return ['success', 'warning', 'error'].includes(variant) ? variant : 'info'
|
|
6199
|
+
},
|
|
6200
|
+
|
|
6201
|
+
effectivePageTabs() {
|
|
6202
|
+
if (!Array.isArray(this.pageTabs) || this.pageTabs.length === 0) {
|
|
6203
|
+
return this.sourcePageTabs
|
|
6204
|
+
}
|
|
6205
|
+
return this.pageTabs
|
|
6206
|
+
.filter((tab) => tab && typeof tab.label === 'string' && tab.label !== '' && (tab.route || tab.to || tab.href))
|
|
6207
|
+
.map((tab, index) => {
|
|
6208
|
+
const to = tab.route
|
|
6209
|
+
? { name: tab.route, ...(tab.params ? { params: tab.params } : {}), ...(tab.query ? { query: tab.query } : {}) }
|
|
6210
|
+
: (tab.to || tab.href)
|
|
6211
|
+
const count = this.pageTabCounts[index]
|
|
6212
|
+
return { id: tab.id || `page-tab-${index}`, label: this.cnTranslate(tab.label), to, ...(typeof count === 'number' ? { count } : {}) }
|
|
6213
|
+
})
|
|
6214
|
+
},
|
|
6215
|
+
|
|
6216
|
+
/**
|
|
6217
|
+
* What the page tab counts depend on, as one key.
|
|
6218
|
+
*
|
|
6219
|
+
* @return {string}
|
|
6220
|
+
* @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-link-its-sibling-pages-as-tabs
|
|
6221
|
+
*/
|
|
6222
|
+
pageTabCountKey() {
|
|
6223
|
+
const tabs = Array.isArray(this.pageTabs) ? this.pageTabs : []
|
|
6224
|
+
const sources = tabs.map((tab) => (tab && tab.countFrom && tab.countFrom.register && tab.countFrom.schema ? tab.countFrom : null))
|
|
6225
|
+
return sources.some(Boolean) ? JSON.stringify(sources) : ''
|
|
6226
|
+
},
|
|
6227
|
+
|
|
6043
6228
|
/**
|
|
6044
6229
|
* The numbers on the quick filters: a named source counts its own
|
|
6045
6230
|
* tabs (`tabCounts()`), a self-fetching page asks OpenRegister.
|
|
@@ -6061,11 +6246,15 @@ export default {
|
|
|
6061
6246
|
* @return {string} The note, translated, or ''.
|
|
6062
6247
|
*/
|
|
6063
6248
|
effectiveFooterNote() {
|
|
6064
|
-
|
|
6065
|
-
|
|
6249
|
+
// The scope's note, else the page's (a preset may have set it),
|
|
6250
|
+
// else the named source's.
|
|
6251
|
+
const scoped = this.activeScopePresentation ? this.activeScopePresentation.footerNote : undefined
|
|
6252
|
+
const footerNote = scoped !== undefined ? scoped : this.footerNote
|
|
6253
|
+
if (footerNote) {
|
|
6254
|
+
return this.cnTranslate(footerNote)
|
|
6066
6255
|
}
|
|
6067
6256
|
const source = this.isNamedSource ? this.namedSource : null
|
|
6068
|
-
return (source && source.footerNote) ||
|
|
6257
|
+
return (source && source.footerNote) || footerNote
|
|
6069
6258
|
},
|
|
6070
6259
|
|
|
6071
6260
|
/**
|
|
@@ -6076,7 +6265,7 @@ export default {
|
|
|
6076
6265
|
* @return {Array<object>|null} The tabs, or null when there are none.
|
|
6077
6266
|
*/
|
|
6078
6267
|
effectiveQuickFilters() {
|
|
6079
|
-
const own = withPersonalLenses(this.quickFilters || this.generatedQuickFilters, this.personalLenses)
|
|
6268
|
+
const own = withPersonalLenses(this.presented('quickFilters') || this.generatedQuickFilters, this.personalLenses)
|
|
6080
6269
|
if (own && own.length > 0) {
|
|
6081
6270
|
return own
|
|
6082
6271
|
}
|
|
@@ -6142,7 +6331,8 @@ export default {
|
|
|
6142
6331
|
* @return {Array<{key: string, label: string, action: string, variant: string, icon: string, format: string}>}
|
|
6143
6332
|
*/
|
|
6144
6333
|
resolvedHeaderButtons() {
|
|
6145
|
-
const
|
|
6334
|
+
const headerButtons = this.presented('headerButtons')
|
|
6335
|
+
const declared = Array.isArray(headerButtons) ? headerButtons : []
|
|
6146
6336
|
return declared
|
|
6147
6337
|
.filter((button) => button && typeof button === 'object' && typeof button.action === 'string' && button.action !== '')
|
|
6148
6338
|
.map((button, index) => {
|
|
@@ -6267,6 +6457,7 @@ export default {
|
|
|
6267
6457
|
for (const [key, raw] of Object.entries(this.effectiveActiveFilters || {})) {
|
|
6268
6458
|
const values = (Array.isArray(raw) ? raw : [raw])
|
|
6269
6459
|
.filter((value) => value !== null && value !== undefined && value !== '')
|
|
6460
|
+
.filter((value) => !this.isFixedFilter(key, value))
|
|
6270
6461
|
.map((value) => this.activeFilterValueLabel(key, value))
|
|
6271
6462
|
if (values.length === 0) {
|
|
6272
6463
|
continue
|
|
@@ -6450,11 +6641,12 @@ export default {
|
|
|
6450
6641
|
* @return {string}
|
|
6451
6642
|
*/
|
|
6452
6643
|
headerMetaText() {
|
|
6453
|
-
|
|
6644
|
+
const headerMeta = this.presented('headerMeta')
|
|
6645
|
+
if (!headerMeta) {
|
|
6454
6646
|
return ''
|
|
6455
6647
|
}
|
|
6456
6648
|
const total = this.effectivePagination?.total
|
|
6457
|
-
return this.cnTranslate(
|
|
6649
|
+
return this.cnTranslate(headerMeta)
|
|
6458
6650
|
.replace('{shown}', String(this.effectiveObjects.length))
|
|
6459
6651
|
.replace('{total}', typeof total === 'number' ? String(total) : '')
|
|
6460
6652
|
},
|
|
@@ -6468,11 +6660,12 @@ export default {
|
|
|
6468
6660
|
// The default count line is the library's own string, so it
|
|
6469
6661
|
// reads "14 van 14" in Dutch; a page's own template goes
|
|
6470
6662
|
// through the app's label lookup.
|
|
6471
|
-
|
|
6663
|
+
const countText = this.presented('countText')
|
|
6664
|
+
if (!countText && !this.countSubtitle) {
|
|
6472
6665
|
return t('nextcloud-vue', '{shown} of {total}', { shown, total })
|
|
6473
6666
|
}
|
|
6474
|
-
if (
|
|
6475
|
-
return this.cnTranslate(
|
|
6667
|
+
if (countText) {
|
|
6668
|
+
return this.cnTranslate(countText)
|
|
6476
6669
|
.replace('{shown}', String(shown))
|
|
6477
6670
|
.replace('{total}', String(total))
|
|
6478
6671
|
}
|
|
@@ -6486,8 +6679,10 @@ export default {
|
|
|
6486
6679
|
|
|
6487
6680
|
/** Add button label — derived from schema.title if not explicitly set */
|
|
6488
6681
|
resolvedAddLabel() {
|
|
6489
|
-
|
|
6490
|
-
|
|
6682
|
+
const scoped = this.activeScopePresentation ? this.activeScopePresentation.addLabel : undefined
|
|
6683
|
+
const addLabel = scoped !== undefined ? scoped : this.addLabel
|
|
6684
|
+
if (addLabel) {
|
|
6685
|
+
return this.cnTranslate(addLabel)
|
|
6491
6686
|
}
|
|
6492
6687
|
// A named source names its own create action. Without this the button
|
|
6493
6688
|
// falls back to a schema-derived noun, and a named source has no
|
|
@@ -6712,6 +6907,14 @@ export default {
|
|
|
6712
6907
|
},
|
|
6713
6908
|
},
|
|
6714
6909
|
|
|
6910
|
+
pageTabCountKey: {
|
|
6911
|
+
immediate: true,
|
|
6912
|
+
/** @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-link-its-sibling-pages-as-tabs */
|
|
6913
|
+
handler() {
|
|
6914
|
+
this.loadPageTabCounts()
|
|
6915
|
+
},
|
|
6916
|
+
},
|
|
6917
|
+
|
|
6715
6918
|
filterStripCountKey: {
|
|
6716
6919
|
immediate: true,
|
|
6717
6920
|
/** @spec openspec/changes/screens-filter-strip/specs/index-filter-strip/spec.md#requirement-an-index-page-can-draw-a-second-filter-strip */
|
|
@@ -6916,6 +7119,7 @@ export default {
|
|
|
6916
7119
|
this.maybeOpenCreateFromQuery()
|
|
6917
7120
|
if (this.folderSidebar) {
|
|
6918
7121
|
this.loadFolderRegister()
|
|
7122
|
+
this.loadFolderGroups()
|
|
6919
7123
|
// Reflect a deep-link filter (e.g. ?caseType=<id>) as the active folder.
|
|
6920
7124
|
const key = this.folderSidebar.filterField || this.folderSidebar.field
|
|
6921
7125
|
const active = key && this.effectiveActiveFilters[key]
|
|
@@ -6979,6 +7183,36 @@ export default {
|
|
|
6979
7183
|
},
|
|
6980
7184
|
|
|
6981
7185
|
methods: {
|
|
7186
|
+
/**
|
|
7187
|
+
* A presentation value: the active scope's when it declares the key,
|
|
7188
|
+
* else this page's own prop (which a query preset may have set).
|
|
7189
|
+
*
|
|
7190
|
+
* @param {string} key One of the query preset keys.
|
|
7191
|
+
* @return {unknown} The value.
|
|
7192
|
+
* @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-a-preset-or-a-scope-sets-the-list-s-presentation
|
|
7193
|
+
*/
|
|
7194
|
+
presented(key) {
|
|
7195
|
+
const scoped = this.activeScopePresentation
|
|
7196
|
+
return scoped[key] !== undefined ? scoped[key] : this.ownPresentation[key]
|
|
7197
|
+
},
|
|
7198
|
+
|
|
7199
|
+
/**
|
|
7200
|
+
* Whether a filter value is one of the query pairs that chose the
|
|
7201
|
+
* preset, so it shows no removable chip.
|
|
7202
|
+
*
|
|
7203
|
+
* @param {string} key The filter key.
|
|
7204
|
+
* @param {unknown} value One filter value.
|
|
7205
|
+
* @return {boolean}
|
|
7206
|
+
* @spec openspec/changes/index-scope-presentation/specs/index-page/spec.md#requirement-the-query-that-chose-a-preset-is-not-a-removable-filter
|
|
7207
|
+
*/
|
|
7208
|
+
isFixedFilter(key, value) {
|
|
7209
|
+
const fixed = this.fixedFilters
|
|
7210
|
+
if (!fixed || !Object.hasOwn(fixed, key)) {
|
|
7211
|
+
return false
|
|
7212
|
+
}
|
|
7213
|
+
return String(fixed[key]) === String(value)
|
|
7214
|
+
},
|
|
7215
|
+
|
|
6982
7216
|
/**
|
|
6983
7217
|
* The manifest page that shows one object of a schema, for a linked
|
|
6984
7218
|
* label. Null without a manifest or a matching detail page.
|
|
@@ -7092,6 +7326,32 @@ export default {
|
|
|
7092
7326
|
]
|
|
7093
7327
|
},
|
|
7094
7328
|
|
|
7329
|
+
/**
|
|
7330
|
+
* Count the lists behind the manifest page tabs (`countFrom`), one list
|
|
7331
|
+
* request each. A failed count shows no number.
|
|
7332
|
+
*
|
|
7333
|
+
* @return {Promise<void>}
|
|
7334
|
+
* @spec openspec/changes/index-page-tabs-notice/specs/index-page/spec.md#requirement-an-index-page-can-link-its-sibling-pages-as-tabs
|
|
7335
|
+
*/
|
|
7336
|
+
async loadPageTabCounts() {
|
|
7337
|
+
const key = this.pageTabCountKey
|
|
7338
|
+
if (key === '') {
|
|
7339
|
+
this.pageTabCounts = {}
|
|
7340
|
+
return
|
|
7341
|
+
}
|
|
7342
|
+
const ctx = typeof this.selfFetchTokenCtx === 'function' ? this.selfFetchTokenCtx() : {}
|
|
7343
|
+
const counts = {}
|
|
7344
|
+
await Promise.all(this.pageTabs.map(async (tab, index) => {
|
|
7345
|
+
const from = tab && tab.countFrom
|
|
7346
|
+
if (from && from.register && from.schema) {
|
|
7347
|
+
counts[index] = await fetchListTotal(from.register, from.schema, from.filter || {}, ctx).catch(() => null)
|
|
7348
|
+
}
|
|
7349
|
+
}))
|
|
7350
|
+
if (key === this.pageTabCountKey) {
|
|
7351
|
+
this.pageTabCounts = counts
|
|
7352
|
+
}
|
|
7353
|
+
},
|
|
7354
|
+
|
|
7095
7355
|
/**
|
|
7096
7356
|
* Read the counts of the `filterStrip` pills in one grouped request,
|
|
7097
7357
|
* narrowed by the page filter and the active quick filter. A failed
|
|
@@ -8525,6 +8785,50 @@ export default {
|
|
|
8525
8785
|
this.$emit('quick-edit-save', { id, patch })
|
|
8526
8786
|
},
|
|
8527
8787
|
|
|
8788
|
+
/**
|
|
8789
|
+
* The buttons an `actions` column shows on a row: the row actions its
|
|
8790
|
+
* `widgetProps.actions` names (by id, else by label), in that order,
|
|
8791
|
+
* that are visible for the row.
|
|
8792
|
+
*
|
|
8793
|
+
* @param {object} col The column.
|
|
8794
|
+
* @param {object} row The row.
|
|
8795
|
+
* @return {Array<{key: string, label: string, variant: string, disabled: boolean}>}
|
|
8796
|
+
* @spec openspec/changes/table-actions-column/specs/index-page/spec.md#requirement-a-column-can-show-row-actions-as-buttons
|
|
8797
|
+
*/
|
|
8798
|
+
actionColumnItems(col, row) {
|
|
8799
|
+
const wanted = Array.isArray(col.widgetProps && col.widgetProps.actions) ? col.widgetProps.actions : []
|
|
8800
|
+
const available = this.rowActionsFor(row)
|
|
8801
|
+
return wanted
|
|
8802
|
+
.map((ref) => available.find((action) => action.id === ref) || available.find((action) => action.label === ref))
|
|
8803
|
+
.filter((action) => action && isRowActionVisible(action, row))
|
|
8804
|
+
.map((action, index) => ({
|
|
8805
|
+
key: action.id || action.label,
|
|
8806
|
+
label: this.cnTranslate(action.label),
|
|
8807
|
+
variant: action.variant || (index === 0 ? 'secondary' : 'tertiary'),
|
|
8808
|
+
disabled: typeof action.disabled === 'function' ? !!action.disabled(row) : action.disabled === true,
|
|
8809
|
+
}))
|
|
8810
|
+
},
|
|
8811
|
+
|
|
8812
|
+
/**
|
|
8813
|
+
* Run one `actions` column button: its handler, then the same `action`
|
|
8814
|
+
* event a row menu entry emits.
|
|
8815
|
+
*
|
|
8816
|
+
* @param {string} key The action's id, else its label.
|
|
8817
|
+
* @param {object} row The row.
|
|
8818
|
+
* @return {void}
|
|
8819
|
+
* @spec openspec/changes/table-actions-column/specs/index-page/spec.md#requirement-a-column-can-show-row-actions-as-buttons
|
|
8820
|
+
*/
|
|
8821
|
+
runColumnAction(key, row) {
|
|
8822
|
+
const action = this.rowActionsFor(row).find((entry) => (entry.id || entry.label) === key)
|
|
8823
|
+
if (!action) {
|
|
8824
|
+
return
|
|
8825
|
+
}
|
|
8826
|
+
if (typeof action.handler === 'function') {
|
|
8827
|
+
action.handler(row)
|
|
8828
|
+
}
|
|
8829
|
+
this.onRowAction(rowActionPayload(action, row))
|
|
8830
|
+
},
|
|
8831
|
+
|
|
8528
8832
|
/**
|
|
8529
8833
|
* Take the server's version of a row after a conflict. Nothing of this
|
|
8530
8834
|
* person's edit is written, and the row in the list is refreshed to
|
|
@@ -8688,6 +8992,39 @@ export default {
|
|
|
8688
8992
|
}
|
|
8689
8993
|
},
|
|
8690
8994
|
|
|
8995
|
+
/**
|
|
8996
|
+
* Load the Nextcloud groups for `folderSidebar.source: 'groups'`, each
|
|
8997
|
+
* with its member count. `folderSidebar.groups` (`[{ id, parent? }]`)
|
|
8998
|
+
* picks and orders them and nests a group under its `parent`; without
|
|
8999
|
+
* it every group shows, by name. A refused request lists none.
|
|
9000
|
+
*
|
|
9001
|
+
* @return {Promise<void>}
|
|
9002
|
+
* @spec openspec/changes/index-groups-users-source/specs/index-page/spec.md#requirement-an-index-page-can-list-nextcloud-groups-and-their-members
|
|
9003
|
+
*/
|
|
9004
|
+
async loadFolderGroups() {
|
|
9005
|
+
const cfg = this.folderSidebar
|
|
9006
|
+
if (!cfg || cfg.source !== 'groups') {
|
|
9007
|
+
return
|
|
9008
|
+
}
|
|
9009
|
+
try {
|
|
9010
|
+
const { default: axios } = await import('@nextcloud/axios')
|
|
9011
|
+
const groups = await fetchGroups(axios, { search: cfg.search || '', limit: cfg.limit || 200 })
|
|
9012
|
+
const declared = Array.isArray(cfg.groups) ? cfg.groups.filter((entry) => entry && entry.id) : null
|
|
9013
|
+
if (!declared) {
|
|
9014
|
+
this.folderGroupList = [...groups].sort((a, b) => a.name.localeCompare(b.name))
|
|
9015
|
+
return
|
|
9016
|
+
}
|
|
9017
|
+
const byId = new Map(groups.map((group) => [group.id, group]))
|
|
9018
|
+
this.folderGroupList = declared
|
|
9019
|
+
.filter((entry) => byId.has(String(entry.id)))
|
|
9020
|
+
.map((entry) => ({ ...byId.get(String(entry.id)), parentId: entry.parent ? String(entry.parent) : null }))
|
|
9021
|
+
} catch (e) {
|
|
9022
|
+
// eslint-disable-next-line no-console
|
|
9023
|
+
console.error('[CnIndexPage] failed to load the Nextcloud groups', e)
|
|
9024
|
+
this.folderGroupList = []
|
|
9025
|
+
}
|
|
9026
|
+
},
|
|
9027
|
+
|
|
8691
9028
|
/**
|
|
8692
9029
|
* Load the folder list from an OpenRegister register/schema for a
|
|
8693
9030
|
* `folderSidebar.source === 'register'` config. Maps each object to
|
|
@@ -9377,6 +9714,9 @@ export default {
|
|
|
9377
9714
|
* @return {boolean} True for the current page.
|
|
9378
9715
|
*/
|
|
9379
9716
|
isActivePageTab(tab) {
|
|
9717
|
+
if (tab.to && typeof tab.to === 'object') {
|
|
9718
|
+
return !!this.$route && tab.to.name !== undefined && this.$route.name === tab.to.name
|
|
9719
|
+
}
|
|
9380
9720
|
const path = this.$route && this.$route.path
|
|
9381
9721
|
return !!path && String(path).replace(/\/+$/, '') === String(tab.to).replace(/\/+$/, '')
|
|
9382
9722
|
},
|