@conduction/nextcloud-vue 2.106.0 → 2.107.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/CnActionDialog/CnActionDialog.vue.js +9 -0
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js.map +1 -0
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +338 -0
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -0
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +249 -0
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -0
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertiesTab.vue2.js +2 -2
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertiesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +145 -138
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +102 -2
- 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/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +83 -6
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +4 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIcon/semanticIcons.js +2 -2
- package/dist/esm/components/CnIcon/semanticIcons.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +389 -20
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +68 -35
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +22 -2
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +69 -5
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +38 -5
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +7 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js +8 -0
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js.map +1 -0
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js +297 -0
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js.map +1 -0
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js +24 -0
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js.map +1 -0
- package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue.js +9 -0
- package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue.js.map +1 -0
- package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue2.js +95 -0
- package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue2.js.map +1 -0
- package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue3.js +123 -0
- package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue3.js.map +1 -0
- package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue.js +1 -1
- package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue2.js +13 -5
- package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue3.js +3 -1
- package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue.js +1 -1
- package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue2.js +49 -23
- package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue3.js +74 -27
- package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue.js +0 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +18 -413
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js +27 -214
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue.js +9 -0
- package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue.js.map +1 -0
- package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue2.js +190 -0
- package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue2.js.map +1 -0
- package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue3.js +270 -0
- package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue3.js.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +56 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +56 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/mixins/savedViewsList.js +235 -0
- package/dist/esm/mixins/savedViewsList.js.map +1 -0
- package/dist/esm/nextcloud-vue.css +348 -108
- package/dist/esm/utils/actionsDispatcher.js +2 -2
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/esm/utils/builtInModals.js +39 -0
- package/dist/esm/utils/builtInModals.js.map +1 -0
- package/dist/esm/utils/mapMarkerColor.js +121 -0
- package/dist/esm/utils/mapMarkerColor.js.map +1 -0
- package/dist/esm/utils/mergeManifestDelta.js +4 -0
- package/dist/esm/utils/mergeManifestDelta.js.map +1 -1
- package/dist/esm/utils/savedViewHelpers.js +59 -7
- package/dist/esm/utils/savedViewHelpers.js.map +1 -1
- package/dist/esm/utils/savedViewMenu.js +154 -0
- package/dist/esm/utils/savedViewMenu.js.map +1 -0
- package/dist/esm/utils/searchGroupSharees.js +50 -15
- package/dist/esm/utils/searchGroupSharees.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 +13351 -10855
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +348 -108
- package/l10n/en.json +56 -1
- package/l10n/nl.json +56 -1
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +545 -0
- package/src/components/CnActionDialog/index.js +12 -0
- package/src/components/CnAppNav/CnAppNav.vue +17 -0
- package/src/components/CnAppRoot/CnAppRoot.vue +102 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +86 -7
- package/src/components/CnIndexPage/CnIndexPage.vue +409 -23
- package/src/components/CnIndexPage/useSelfFetchList.js +21 -1
- package/src/components/CnIndexSidebar/CnIndexSidebar.md +2 -0
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +91 -1
- package/src/components/CnMapWidget/CnMapWidget.vue +16 -1
- package/src/components/CnPartyPicker/CnPartyPicker.vue +317 -0
- package/src/components/CnPartyPicker/index.js +11 -0
- package/src/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue +192 -0
- package/src/components/CnSavedViewEditDialog/index.js +11 -0
- package/src/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue +21 -6
- package/src/components/CnSavedViewShareFields/CnSavedViewShareFields.vue +130 -37
- package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +36 -599
- package/src/components/CnSavedViewsPanel/CnSavedViewsPanel.vue +459 -0
- package/src/components/CnSavedViewsPanel/index.js +11 -0
- package/src/components/index.js +4 -0
- package/src/css/index-page.css +16 -0
- package/src/css/look-board-index.css +5 -3
- package/src/css/look-board.css +18 -3
- package/src/index.js +4 -0
- package/src/mixins/savedViewsList.js +231 -0
- package/src/schemas/app-manifest-v2.schema.json +98 -3
- package/src/utils/actionsDispatcher.js +2 -2
- package/src/utils/builtInModals.js +35 -0
- package/src/utils/mapMarkerColor.js +117 -0
- package/src/utils/mergeManifestDelta.js +4 -0
- package/src/utils/savedViewHelpers.js +58 -6
- package/src/utils/savedViewMenu.js +150 -0
- package/src/utils/searchGroupSharees.js +49 -14
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -323,9 +323,9 @@
|
|
|
323
323
|
the app-specific buttons in `#actions`, with Add sitting between
|
|
324
324
|
the two groups rather than before both (dossiq Cases/Queue). -->
|
|
325
325
|
<template v-if="isEditMode || barShowsExportMenu || barShowsSavedViews" #actions-end>
|
|
326
|
-
<!-- Saved views (opt-in via `allowSavedViews`):
|
|
327
|
-
|
|
328
|
-
|
|
326
|
+
<!-- Saved views (opt-in via `allowSavedViews`): the toolbar keeps
|
|
327
|
+
"Save view" and, under the board look, the chips. The list
|
|
328
|
+
and every per-view action live in the sidebar's Filters tab. -->
|
|
329
329
|
<CnSavedViewsControl
|
|
330
330
|
v-if="barShowsSavedViews"
|
|
331
331
|
:views="viewsForControl"
|
|
@@ -334,12 +334,7 @@
|
|
|
334
334
|
:counts="savedViewCounts"
|
|
335
335
|
:selectedViewId="appliedSavedViewId"
|
|
336
336
|
@apply="onApplySavedView"
|
|
337
|
-
@saveRequest="showSaveViewDialog = true"
|
|
338
|
-
@shareRequest="onShareViewRequest"
|
|
339
|
-
@presentationRequest="onPresentationViewRequest"
|
|
340
|
-
@updateRequest="onUpdateViewRequest"
|
|
341
|
-
@copyRequest="onCopyViewRequest"
|
|
342
|
-
@deleteRequest="onDeleteViewRequest" />
|
|
337
|
+
@saveRequest="showSaveViewDialog = true" />
|
|
343
338
|
<!-- Native Export menu (opt-in via `allowExport` + schema.exportable):
|
|
344
339
|
CSV/Excel entries navigate to OR's export-leaf URL, passing the
|
|
345
340
|
current route's query params through as filters. -->
|
|
@@ -551,6 +546,14 @@
|
|
|
551
546
|
@confirm="onPresentationViewConfirm"
|
|
552
547
|
@close="viewPendingPresentation = null" />
|
|
553
548
|
|
|
549
|
+
<!-- Edit-a-saved-view dialog (saved-views-manage-and-defaults) -->
|
|
550
|
+
<CnSavedViewEditDialog
|
|
551
|
+
v-if="viewPendingEdit"
|
|
552
|
+
ref="editViewDialog"
|
|
553
|
+
:view="viewPendingEdit"
|
|
554
|
+
@confirm="onEditViewConfirm"
|
|
555
|
+
@close="viewPendingEdit = null" />
|
|
556
|
+
|
|
554
557
|
<!-- Share-a-saved-view dialog (saved-views-shared-by-role) -->
|
|
555
558
|
<CnSavedViewShareDialog
|
|
556
559
|
v-if="viewPendingShare"
|
|
@@ -564,9 +567,9 @@
|
|
|
564
567
|
v-if="viewPendingDelete"
|
|
565
568
|
ref="deleteViewConfirmDialog"
|
|
566
569
|
variant="error"
|
|
567
|
-
:dialogTitle="t('nextcloud-vue', 'Delete view')"
|
|
570
|
+
:dialogTitle="t('nextcloud-vue', 'Delete view?')"
|
|
568
571
|
:message="deleteViewMessage"
|
|
569
|
-
:confirmLabel="t('nextcloud-vue', 'Delete')"
|
|
572
|
+
:confirmLabel="t('nextcloud-vue', 'Delete view')"
|
|
570
573
|
@confirm="onDeleteViewConfirm"
|
|
571
574
|
@close="viewPendingDelete = null" />
|
|
572
575
|
|
|
@@ -1131,6 +1134,16 @@
|
|
|
1131
1134
|
{{ t('nextcloud-vue', 'File matches are limited to the best 50.') }}
|
|
1132
1135
|
</p>
|
|
1133
1136
|
|
|
1137
|
+
<!-- The map's count line (`mapConfig.count`) and the note when a map
|
|
1138
|
+
that plots every row reached its limit. -->
|
|
1139
|
+
<div
|
|
1140
|
+
v-if="mapCountLine || mapCapNote"
|
|
1141
|
+
class="cn-index-page__map-count"
|
|
1142
|
+
data-testid="cn-index-map-count">
|
|
1143
|
+
<span v-if="mapCountLine" data-testid="cn-index-map-count-line">{{ mapCountLine }}</span>
|
|
1144
|
+
<span v-if="mapCapNote" class="cn-index-page__map-cap" data-testid="cn-index-map-cap">{{ mapCapNote }}</span>
|
|
1145
|
+
</div>
|
|
1146
|
+
|
|
1134
1147
|
<!-- The board view's footer: it holds every row it loaded, so it
|
|
1135
1148
|
counts them and offers the next batch instead of pages. -->
|
|
1136
1149
|
<div
|
|
@@ -1248,8 +1261,12 @@
|
|
|
1248
1261
|
:pinnedCount="pinnedColumnCount"
|
|
1249
1262
|
:sortOptions="sidebarSortOptions"
|
|
1250
1263
|
:currentSort="currentSortKeys"
|
|
1264
|
+
:savedViews="savedViewsForSidebar"
|
|
1265
|
+
:activeTab="sidebarActiveTab"
|
|
1251
1266
|
v-bind="sidebarSearchProps"
|
|
1252
1267
|
@update:open="sidebarOpen = $event"
|
|
1268
|
+
@tabChange="sidebarActiveTab = $event"
|
|
1269
|
+
@savedView="onSavedViewAction"
|
|
1253
1270
|
@search="onSearchEvent"
|
|
1254
1271
|
@columnsChange="onColumnsEvent"
|
|
1255
1272
|
@columnsReorder="onColumnsReorder"
|
|
@@ -1316,12 +1333,13 @@ import { isModifiedClick, openRowTarget } from '../../utils/linkNavigation.js'
|
|
|
1316
1333
|
import { resolveClaimedTeams, resolveClaimTokens, splitViewsIntoTabs, viewAsTab, viewIdOf } from '../../utils/listLenses.js'
|
|
1317
1334
|
import { LIST_SHORTCUTS, listPaletteCommands, shortcutFor } from '../../utils/listShortcuts.js'
|
|
1318
1335
|
import { mapListItems } from '../../utils/mapList.js'
|
|
1336
|
+
import { markerColorOf, normalizeMarkerColor, resolveCssColor } from '../../utils/mapMarkerColor.js'
|
|
1319
1337
|
import { multiKeySort } from '../../utils/multiKeySort.js'
|
|
1320
1338
|
import { fetchGroups } from '../../utils/nextcloudDirectory.js'
|
|
1321
1339
|
import { OBJECTS_CHANGED_EVENT } from '../../utils/objectSignals.js'
|
|
1322
1340
|
import { objectUrlOf, patchObject } from '../../utils/objectWrite.js'
|
|
1323
1341
|
import { withPersonalLenses } from '../../utils/personalLenses.js'
|
|
1324
|
-
import { resolveDeepTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js'
|
|
1342
|
+
import { resolveDeepTokens, resolveFilterTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js'
|
|
1325
1343
|
import { resolveRowActions } from '../../utils/resolveRowActions.js'
|
|
1326
1344
|
import { resolveFilterMap } from '../../utils/routeFilters.js'
|
|
1327
1345
|
import { availableRowActions, DEFAULT_ROW_ACTION_FIELD, refusalReasonFor, undeclaredRowActions, withoutViewWhenRowOpensDetail } from '../../utils/rowActionAvailability.js'
|
|
@@ -1329,7 +1347,7 @@ import { isRowActionVisible, rowActionPayload } from '../../utils/rowActionItem.
|
|
|
1329
1347
|
import { isNewTabClick, isNewTabHandled, isRowMiddleClick, markNewTabHandled, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'
|
|
1330
1348
|
import { compileRowClass } from '../../utils/rowClassRules.js'
|
|
1331
1349
|
import { DEFAULT_ROW_INDICATOR_CAP } from '../../utils/rowIndicators.js'
|
|
1332
|
-
import { buildRouteQueryFromViewState, buildViewCreatePayload, extractViewState, extractViewStateFromRouteQuery, normalizeSharedWith, savedViewScope, viewMatchesScope } from '../../utils/savedViewHelpers.js'
|
|
1350
|
+
import { buildRouteQueryFromViewState, buildViewCreatePayload, defaultFilterViews, extractViewState, extractViewStateFromRouteQuery, normalizeSharedWith, savedViewScope, viewMatchesScope } from '../../utils/savedViewHelpers.js'
|
|
1333
1351
|
import { columnsFromSchema, fieldsFromSchema } from '../../utils/schema.js'
|
|
1334
1352
|
import { resolveScopeLayout, resolveScopePresentation } from '../../utils/scopeListLayout.js'
|
|
1335
1353
|
import { orderToSortKeys } from '../../utils/sortOrder.js'
|
|
@@ -1359,6 +1377,7 @@ import { CnPageHeader } from '../CnPageHeader/index.js'
|
|
|
1359
1377
|
import { CnPagination } from '../CnPagination/index.js'
|
|
1360
1378
|
import { CnQuickFilterBar } from '../CnQuickFilterBar/index.js'
|
|
1361
1379
|
import { CnRowActions } from '../CnRowActions/index.js'
|
|
1380
|
+
import { CnSavedViewEditDialog } from '../CnSavedViewEditDialog/index.js'
|
|
1362
1381
|
import { CnSavedViewPresentationDialog } from '../CnSavedViewPresentationDialog/index.js'
|
|
1363
1382
|
import { CnSavedViewsControl } from '../CnSavedViewsControl/index.js'
|
|
1364
1383
|
import { CnSavedViewShareDialog } from '../CnSavedViewShareDialog/index.js'
|
|
@@ -1371,7 +1390,7 @@ import { orderColumns, personalColumnsKey, reconcilePersonalColumns } from './pe
|
|
|
1371
1390
|
import { createSelfModeActions, resolveRowTarget } from './selfModeActions.js'
|
|
1372
1391
|
import { applyRowPatches, normalisePaneWidth, rowIdOf, splitLayoutFor } from './splitView.js'
|
|
1373
1392
|
import { useNamedSource } from './useNamedSource.js'
|
|
1374
|
-
import { BOARD_PAGE_SIZE, resolveInitialQuickFilterIndex, useSelfFetchList } from './useSelfFetchList.js'
|
|
1393
|
+
import { BOARD_PAGE_SIZE, mapPlotAllLimitOf, resolveInitialQuickFilterIndex, useSelfFetchList } from './useSelfFetchList.js'
|
|
1375
1394
|
|
|
1376
1395
|
/** Rows fetched for one month in calendar mode. */
|
|
1377
1396
|
const CALENDAR_PAGE_SIZE = 200
|
|
@@ -1653,6 +1672,7 @@ export default {
|
|
|
1653
1672
|
CnIndexSidebar,
|
|
1654
1673
|
CnSavedViewsControl,
|
|
1655
1674
|
CnSavedViewPresentationDialog,
|
|
1675
|
+
CnSavedViewEditDialog,
|
|
1656
1676
|
CnSavedViewShareDialog,
|
|
1657
1677
|
CnSaveViewDialog,
|
|
1658
1678
|
CnConfirmDialog,
|
|
@@ -1724,6 +1744,12 @@ export default {
|
|
|
1724
1744
|
* simply has no held order instead of failing to render.
|
|
1725
1745
|
*/
|
|
1726
1746
|
cnUserPreferences: { default: null },
|
|
1747
|
+
/**
|
|
1748
|
+
* The saved views this user put in the app menu, held by CnAppRoot:
|
|
1749
|
+
* `{ entries, toggle(entry) }`. Absent without the shell, and then
|
|
1750
|
+
* the sidebar offers no Add to menu.
|
|
1751
|
+
*/
|
|
1752
|
+
cnSavedViewMenu: { default: null },
|
|
1727
1753
|
/**
|
|
1728
1754
|
* Consumer translation function, provided by CnAppRoot as
|
|
1729
1755
|
* `cnTranslate: this.translate` (bound to the host app's id). Column and
|
|
@@ -2906,6 +2932,17 @@ export default {
|
|
|
2906
2932
|
default: '',
|
|
2907
2933
|
},
|
|
2908
2934
|
|
|
2935
|
+
/**
|
|
2936
|
+
* Views the app ships for this page (`config.defaultSavedViews`), each
|
|
2937
|
+
* `{ slug, name, filters, search?, sort?, label? }`. Listed read-only
|
|
2938
|
+
* above the user's own saved views, never stored; a user may apply one
|
|
2939
|
+
* or save a copy. `@`-tokens in `filters` resolve when it is applied.
|
|
2940
|
+
*/
|
|
2941
|
+
defaultSavedViews: {
|
|
2942
|
+
type: Array,
|
|
2943
|
+
default: () => [],
|
|
2944
|
+
},
|
|
2945
|
+
|
|
2909
2946
|
/** Property name used to display item names in dialogs */
|
|
2910
2947
|
massActionNameField: {
|
|
2911
2948
|
type: String,
|
|
@@ -4013,6 +4050,10 @@ export default {
|
|
|
4013
4050
|
headerMetaCountValues: {},
|
|
4014
4051
|
/** The row the pointer is on in the map list, by key; '' for none. */
|
|
4015
4052
|
activeMapKey: '',
|
|
4053
|
+
/** The rows `mapConfig.markerColor.source` points at, or null before they load. */
|
|
4054
|
+
mapColorRefs: null,
|
|
4055
|
+
/** The page size to restore when leaving a map that plots every row. */
|
|
4056
|
+
mapPrevPageSize: this.viewMode === 'map' && mapPlotAllLimitOf(this.mapConfig) > 0 ? ((this.pagination && this.pagination.limit) || 20) : null,
|
|
4016
4057
|
/** The tabs `quickFiltersFrom` produced, or null before they load. */
|
|
4017
4058
|
generatedQuickFilters: null,
|
|
4018
4059
|
/** Count per saved-view id, for the views control; null = none. */
|
|
@@ -4080,6 +4121,8 @@ export default {
|
|
|
4080
4121
|
// content (table / cards) starts at the top and fills the width;
|
|
4081
4122
|
// opened on demand via the actions-bar toggle.
|
|
4082
4123
|
sidebarOpen: false,
|
|
4124
|
+
/** The sidebar tab to show; follows the user's own tab changes. */
|
|
4125
|
+
sidebarActiveTab: '',
|
|
4083
4126
|
// Saved views (saved-views-ui): the fetched view list, its
|
|
4084
4127
|
// loading flag, the save-dialog toggle, and the view awaiting
|
|
4085
4128
|
// delete confirmation.
|
|
@@ -4089,6 +4132,8 @@ export default {
|
|
|
4089
4132
|
viewPendingDelete: null,
|
|
4090
4133
|
/** The own view whose audience is being changed (CnSavedViewShareDialog), or null. */
|
|
4091
4134
|
viewPendingShare: null,
|
|
4135
|
+
/** The own view being renamed or re-filtered (CnSavedViewEditDialog), or null. */
|
|
4136
|
+
viewPendingEdit: null,
|
|
4092
4137
|
/** The view whose presentation is being changed (CnSavedViewPresentationDialog), or null. */
|
|
4093
4138
|
viewPendingPresentation: null,
|
|
4094
4139
|
// Split view (case-page-and-list-as-a-place). `splitRowPatches` holds
|
|
@@ -5260,7 +5305,63 @@ export default {
|
|
|
5260
5305
|
* @return {Array<object>} The views.
|
|
5261
5306
|
*/
|
|
5262
5307
|
viewsForControl() {
|
|
5263
|
-
return this.splitSavedViews.control
|
|
5308
|
+
return [...this.defaultFilterViews, ...this.splitSavedViews.control]
|
|
5309
|
+
},
|
|
5310
|
+
|
|
5311
|
+
/**
|
|
5312
|
+
* What the sidebar's saved-views panel shows, or null when the page
|
|
5313
|
+
* does not offer saved views.
|
|
5314
|
+
*
|
|
5315
|
+
* @return {object|null}
|
|
5316
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-6
|
|
5317
|
+
*/
|
|
5318
|
+
savedViewsForSidebar() {
|
|
5319
|
+
if (!this.allowSavedViews) {
|
|
5320
|
+
return null
|
|
5321
|
+
}
|
|
5322
|
+
return {
|
|
5323
|
+
views: this.viewsForControl,
|
|
5324
|
+
loading: this.savedViewsLoading,
|
|
5325
|
+
currentUserId: this.currentSavedViewsUserId,
|
|
5326
|
+
counts: this.savedViewCounts,
|
|
5327
|
+
selectedViewId: this.appliedSavedViewId,
|
|
5328
|
+
menuIds: this.savedViewMenuIds,
|
|
5329
|
+
}
|
|
5330
|
+
},
|
|
5331
|
+
|
|
5332
|
+
/**
|
|
5333
|
+
* The route name this page's menu entries point at.
|
|
5334
|
+
*
|
|
5335
|
+
* @return {string}
|
|
5336
|
+
*/
|
|
5337
|
+
savedViewPage() {
|
|
5338
|
+
return (this.$route && typeof this.$route.name === 'string') ? this.$route.name : ''
|
|
5339
|
+
},
|
|
5340
|
+
|
|
5341
|
+
/**
|
|
5342
|
+
* The ids of this page's views in the app menu, or null when there is
|
|
5343
|
+
* no menu to add to.
|
|
5344
|
+
*
|
|
5345
|
+
* @return {Array<string>|null}
|
|
5346
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-7
|
|
5347
|
+
*/
|
|
5348
|
+
savedViewMenuIds() {
|
|
5349
|
+
const menu = this.cnSavedViewMenu
|
|
5350
|
+
if (!menu || typeof menu.toggle !== 'function' || this.savedViewPage === '') {
|
|
5351
|
+
return null
|
|
5352
|
+
}
|
|
5353
|
+
return (menu.entries || []).filter((e) => e.page === this.savedViewPage).map((e) => String(e.id))
|
|
5354
|
+
},
|
|
5355
|
+
|
|
5356
|
+
/**
|
|
5357
|
+
* The page's `defaultSavedViews` as read-only views.
|
|
5358
|
+
*
|
|
5359
|
+
* @return {Array<object>} The views.
|
|
5360
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-4
|
|
5361
|
+
*/
|
|
5362
|
+
defaultFilterViews() {
|
|
5363
|
+
const defaults = (Array.isArray(this.defaultSavedViews) ? this.defaultSavedViews : []).map((entry) => (entry && typeof entry.name === 'string' ? { ...entry, name: this.cnTranslate(entry.name) } : entry))
|
|
5364
|
+
return defaultFilterViews(defaults, this.savedViewsPage)
|
|
5264
5365
|
},
|
|
5265
5366
|
|
|
5266
5367
|
/**
|
|
@@ -5916,11 +6017,13 @@ export default {
|
|
|
5916
6017
|
if (!geometry) {
|
|
5917
6018
|
continue
|
|
5918
6019
|
}
|
|
6020
|
+
const markerColor = resolveCssColor(markerColorOf(row, this.mapMarkerColor, this.mapColorRefsById))
|
|
5919
6021
|
features.push({
|
|
5920
6022
|
type: 'Feature',
|
|
5921
6023
|
geometry,
|
|
5922
6024
|
properties: {
|
|
5923
6025
|
[this.rowKey]: row[this.rowKey],
|
|
6026
|
+
...(markerColor ? { markerColor } : {}),
|
|
5924
6027
|
...(this.mapConfig.popupField ? { [this.mapConfig.popupField]: row[this.mapConfig.popupField] } : {}),
|
|
5925
6028
|
...(numbers && numbers.has(row) ? { markerNumber: numbers.get(row), markerActive: this.activeMapKey === String(row[this.rowKey]) } : {}),
|
|
5926
6029
|
},
|
|
@@ -5949,6 +6052,80 @@ export default {
|
|
|
5949
6052
|
return this.mapConfig.clustering !== false
|
|
5950
6053
|
},
|
|
5951
6054
|
|
|
6055
|
+
/**
|
|
6056
|
+
* The marker colour rule (`mapConfig.markerColor`), or null.
|
|
6057
|
+
*
|
|
6058
|
+
* @return {object|null} The normalised rule.
|
|
6059
|
+
* @spec openspec/changes/index-map-parity/specs/index-page/spec.md#requirement-a-marker-can-take-its-colour-from-a-field
|
|
6060
|
+
*/
|
|
6061
|
+
mapMarkerColor() {
|
|
6062
|
+
return normalizeMarkerColor(this.mapConfig && this.mapConfig.markerColor)
|
|
6063
|
+
},
|
|
6064
|
+
|
|
6065
|
+
/** @return {Map<string, object>} The marker colour source rows by id. */
|
|
6066
|
+
mapColorRefsById() {
|
|
6067
|
+
return new Map((this.mapColorRefs || []).map((row) => [refIdOf(row), row]))
|
|
6068
|
+
},
|
|
6069
|
+
|
|
6070
|
+
/** @return {string} Changes when the marker colour source must be read. */
|
|
6071
|
+
mapColorFetchKey() {
|
|
6072
|
+
const source = this.mapMarkerColor && this.mapMarkerColor.source
|
|
6073
|
+
if (this.currentViewMode !== 'map' || !source) {
|
|
6074
|
+
return ''
|
|
6075
|
+
}
|
|
6076
|
+
return [this.mapMarkerColor.field, source.register || '', source.schema || '', this.effectiveSchema ? 1 : 0].join('|')
|
|
6077
|
+
},
|
|
6078
|
+
|
|
6079
|
+
/**
|
|
6080
|
+
* How many rows the map plots when it plots every matching row
|
|
6081
|
+
* (`mapConfig.plotAll`: `true` for 500, or a
|
|
6082
|
+
* number), 0 when it plots the current page.
|
|
6083
|
+
*
|
|
6084
|
+
* @return {number} The limit.
|
|
6085
|
+
* @spec openspec/changes/index-map-parity/specs/index-page/spec.md#requirement-the-map-can-plot-every-matching-row
|
|
6086
|
+
*/
|
|
6087
|
+
mapPlotAllLimit() {
|
|
6088
|
+
return mapPlotAllLimitOf(this.mapConfig)
|
|
6089
|
+
},
|
|
6090
|
+
|
|
6091
|
+
/** @return {number} The rows that match the filters. */
|
|
6092
|
+
mapMatchTotal() {
|
|
6093
|
+
return Math.max(this.displayObjects.length, Number(this.effectivePagination?.total || 0))
|
|
6094
|
+
},
|
|
6095
|
+
|
|
6096
|
+
/**
|
|
6097
|
+
* The count line under the map (`mapConfig.count`): `true` for "Showing
|
|
6098
|
+
* {located} of {total} located", or a template with `{located}` and
|
|
6099
|
+
* `{total}` through the host's translate. '' when not asked for.
|
|
6100
|
+
*
|
|
6101
|
+
* @return {string} The line.
|
|
6102
|
+
* @spec openspec/changes/index-map-parity/specs/index-page/spec.md#requirement-the-map-can-say-how-many-rows-it-placed
|
|
6103
|
+
*/
|
|
6104
|
+
mapCountLine() {
|
|
6105
|
+
const count = this.mapConfig && this.mapConfig.count
|
|
6106
|
+
if (this.currentViewMode !== 'map' || !count) {
|
|
6107
|
+
return ''
|
|
6108
|
+
}
|
|
6109
|
+
const vars = { located: this.mapMarkers.features.length, total: this.mapMatchTotal }
|
|
6110
|
+
if (typeof count === 'string' && count !== '') {
|
|
6111
|
+
return this.cnTranslate(count).replace(/\{(located|total)\}/g, (_, key) => String(vars[key]))
|
|
6112
|
+
}
|
|
6113
|
+
return t('nextcloud-vue', 'Showing {located} of {total} located', vars)
|
|
6114
|
+
},
|
|
6115
|
+
|
|
6116
|
+
/**
|
|
6117
|
+
* The note when a map that plots every row hit its limit.
|
|
6118
|
+
*
|
|
6119
|
+
* @return {string} The note, or ''.
|
|
6120
|
+
*/
|
|
6121
|
+
mapCapNote() {
|
|
6122
|
+
const limit = this.mapPlotAllLimit
|
|
6123
|
+
if (this.currentViewMode !== 'map' || limit === 0 || this.mapMatchTotal <= this.displayObjects.length) {
|
|
6124
|
+
return ''
|
|
6125
|
+
}
|
|
6126
|
+
return t('nextcloud-vue', 'The map shows the first {limit} of {total}. Narrow the filters to see the rest.', { limit: this.displayObjects.length, total: this.mapMatchTotal })
|
|
6127
|
+
},
|
|
6128
|
+
|
|
5952
6129
|
/** @return {number|undefined} The map's initial zoom (`mapConfig.zoom`), when a number. */
|
|
5953
6130
|
mapZoom() {
|
|
5954
6131
|
const zoom = this.mapConfig && this.mapConfig.zoom
|
|
@@ -6300,7 +6477,14 @@ export default {
|
|
|
6300
6477
|
if (!this.viewPendingDelete) {
|
|
6301
6478
|
return ''
|
|
6302
6479
|
}
|
|
6303
|
-
|
|
6480
|
+
const view = this.viewPendingDelete
|
|
6481
|
+
const parts = [t('nextcloud-vue', 'The view "{name}" leaves your list and the menu on the left.', { name: view.name })]
|
|
6482
|
+
const audience = normalizeSharedWith(view.sharedWith).map((e) => e.user || e.group)
|
|
6483
|
+
if (audience.length > 0) {
|
|
6484
|
+
parts.push(t('nextcloud-vue', 'It is shared with {names}; it leaves their lists too.', { names: audience.join(', ') }))
|
|
6485
|
+
}
|
|
6486
|
+
parts.push(t('nextcloud-vue', 'The items themselves stay. This cannot be undone.'))
|
|
6487
|
+
return parts.join(' ')
|
|
6304
6488
|
},
|
|
6305
6489
|
|
|
6306
6490
|
/** Sort key / order: list state in self-fetch mode, else the props. */
|
|
@@ -7349,12 +7533,17 @@ export default {
|
|
|
7349
7533
|
/**
|
|
7350
7534
|
* Effective sidebar configuration. Returns the sidebar config object
|
|
7351
7535
|
* when `sidebar.enabled === true`, otherwise an `{ enabled: false }`
|
|
7352
|
-
* stub so the embedded CnIndexSidebar is not mounted.
|
|
7536
|
+
* stub so the embedded CnIndexSidebar is not mounted. A page that
|
|
7537
|
+
* offers saved views gets the sidebar unless it switched it off
|
|
7538
|
+
* with `enabled: false`: the saved views live in its Search tab.
|
|
7353
7539
|
*/
|
|
7354
7540
|
resolvedSidebar() {
|
|
7355
|
-
if (this.sidebar && this.sidebar.enabled !== false) {
|
|
7541
|
+
if (this.sidebar && this.sidebar.enabled !== false && (this.sidebar.enabled || !this.allowSavedViews)) {
|
|
7356
7542
|
return this.sidebar
|
|
7357
7543
|
}
|
|
7544
|
+
if (this.allowSavedViews && !(this.sidebar && this.sidebar.enabled === false)) {
|
|
7545
|
+
return { ...(this.sidebar || {}), enabled: true }
|
|
7546
|
+
}
|
|
7358
7547
|
return { enabled: false }
|
|
7359
7548
|
},
|
|
7360
7549
|
|
|
@@ -7434,6 +7623,8 @@ export default {
|
|
|
7434
7623
|
pinnedCount: this.pinnedColumnCount,
|
|
7435
7624
|
sortOptions: this.sidebarSortOptions,
|
|
7436
7625
|
currentSort: this.currentSortKeys,
|
|
7626
|
+
savedViews: this.savedViewsForSidebar,
|
|
7627
|
+
activeTab: this.sidebarActiveTab,
|
|
7437
7628
|
...this.sidebarSearchProps,
|
|
7438
7629
|
}
|
|
7439
7630
|
},
|
|
@@ -7487,12 +7678,25 @@ export default {
|
|
|
7487
7678
|
this.applyViewModeFromRoute()
|
|
7488
7679
|
},
|
|
7489
7680
|
|
|
7681
|
+
'$route.query.savedView': function() {
|
|
7682
|
+
this.applySavedViewFromRoute()
|
|
7683
|
+
},
|
|
7684
|
+
|
|
7490
7685
|
routeViewModes() {
|
|
7491
7686
|
if (this.routeViewPending) {
|
|
7492
7687
|
this.applyViewModeFromRoute()
|
|
7493
7688
|
}
|
|
7494
7689
|
},
|
|
7495
7690
|
|
|
7691
|
+
mapColorFetchKey: {
|
|
7692
|
+
immediate: true,
|
|
7693
|
+
handler(key) {
|
|
7694
|
+
if (key !== '') {
|
|
7695
|
+
this.loadMapColorSource()
|
|
7696
|
+
}
|
|
7697
|
+
},
|
|
7698
|
+
},
|
|
7699
|
+
|
|
7496
7700
|
boardFetchKey: {
|
|
7497
7701
|
immediate: true,
|
|
7498
7702
|
handler(key) {
|
|
@@ -7613,6 +7817,11 @@ export default {
|
|
|
7613
7817
|
listSize = this.boardPrevPageSize || 20
|
|
7614
7818
|
this.boardPrevPageSize = null
|
|
7615
7819
|
}
|
|
7820
|
+
const leftMapPlotAll = previous === 'map' && this.mapPrevPageSize !== null
|
|
7821
|
+
if (leftMapPlotAll) {
|
|
7822
|
+
listSize = this.mapPrevPageSize
|
|
7823
|
+
this.mapPrevPageSize = null
|
|
7824
|
+
}
|
|
7616
7825
|
let size = null
|
|
7617
7826
|
if (mode === 'calendar') {
|
|
7618
7827
|
this.calendarPrevPageSize = listSize
|
|
@@ -7620,7 +7829,10 @@ export default {
|
|
|
7620
7829
|
} else if (mode === 'board') {
|
|
7621
7830
|
this.boardPrevPageSize = listSize
|
|
7622
7831
|
size = BOARD_PAGE_SIZE
|
|
7623
|
-
} else if (
|
|
7832
|
+
} else if (mode === 'map' && this.mapPlotAllLimit > 0 && !this.isNamedSource) {
|
|
7833
|
+
this.mapPrevPageSize = listSize
|
|
7834
|
+
size = this.mapPlotAllLimit
|
|
7835
|
+
} else if (previous === 'calendar' || previous === 'board' || leftMapPlotAll) {
|
|
7624
7836
|
size = listSize
|
|
7625
7837
|
}
|
|
7626
7838
|
if (size !== null && typeof this.list.onPageSizeChange === 'function') {
|
|
@@ -9027,13 +9239,21 @@ export default {
|
|
|
9027
9239
|
* (same resulting path/query) is swallowed.
|
|
9028
9240
|
*
|
|
9029
9241
|
* @param {{filters?: object, search?: string, sortKey?: ?string, sortOrder?: string, sortKeys?: Array<{key: string, order: string}>}} state Current view state.
|
|
9242
|
+
* @param {{savedView?: string}} [options] The saved view the address keeps naming, or none.
|
|
9030
9243
|
* @return {void}
|
|
9031
9244
|
*/
|
|
9032
|
-
persistViewStateToRoute(state) {
|
|
9245
|
+
persistViewStateToRoute(state, { savedView = '' } = {}) {
|
|
9033
9246
|
if (!this.$router || !this.$route) {
|
|
9034
9247
|
return
|
|
9035
9248
|
}
|
|
9036
9249
|
const query = { ...this.$route.query }
|
|
9250
|
+
// The menu entry of a saved view is active while the address names
|
|
9251
|
+
// it; any other change to the filters is no longer that view.
|
|
9252
|
+
if (savedView !== '') {
|
|
9253
|
+
query.savedView = savedView
|
|
9254
|
+
} else {
|
|
9255
|
+
delete query.savedView
|
|
9256
|
+
}
|
|
9037
9257
|
for (const key of this.persistedFilterKeys) {
|
|
9038
9258
|
delete query[key]
|
|
9039
9259
|
}
|
|
@@ -9110,6 +9330,30 @@ export default {
|
|
|
9110
9330
|
this.$emit('clear-filters')
|
|
9111
9331
|
},
|
|
9112
9332
|
|
|
9333
|
+
/**
|
|
9334
|
+
* Read the rows `mapConfig.markerColor.source` points at, once.
|
|
9335
|
+
*
|
|
9336
|
+
* @return {Promise<void>}
|
|
9337
|
+
*/
|
|
9338
|
+
async loadMapColorSource() {
|
|
9339
|
+
const rule = this.mapMarkerColor
|
|
9340
|
+
if (!rule || !rule.source || this.mapColorRefs !== null) {
|
|
9341
|
+
return
|
|
9342
|
+
}
|
|
9343
|
+
const property = this.effectiveSchema?.properties?.[rule.field] || null
|
|
9344
|
+
const target = referenceTargetOf(rule.source, { register: this.register, property })
|
|
9345
|
+
if (!target.register || !target.schema) {
|
|
9346
|
+
return
|
|
9347
|
+
}
|
|
9348
|
+
let rows
|
|
9349
|
+
try {
|
|
9350
|
+
rows = await fetchReferenceObjects({ ...target, filter: rule.source.filter || {} })
|
|
9351
|
+
} catch {
|
|
9352
|
+
rows = []
|
|
9353
|
+
}
|
|
9354
|
+
this.mapColorRefs = Array.isArray(rows) ? rows : []
|
|
9355
|
+
},
|
|
9356
|
+
|
|
9113
9357
|
/**
|
|
9114
9358
|
* Fetch what the board view needs: the rows of a reference column
|
|
9115
9359
|
* field (once per field) and the narrowing select's options.
|
|
@@ -10106,6 +10350,10 @@ export default {
|
|
|
10106
10350
|
'filter-change': (event) => this.onFilterEvent(event),
|
|
10107
10351
|
'clear-filters': () => this.onClearFilters(),
|
|
10108
10352
|
'sort-change': (keys) => this.onSidebarSortChange(keys),
|
|
10353
|
+
'saved-view': (event) => this.onSavedViewAction(event),
|
|
10354
|
+
'tab-change': (tab) => {
|
|
10355
|
+
this.sidebarActiveTab = tab
|
|
10356
|
+
},
|
|
10109
10357
|
},
|
|
10110
10358
|
}
|
|
10111
10359
|
},
|
|
@@ -10750,6 +10998,13 @@ export default {
|
|
|
10750
10998
|
this.savedViewsLoading = true
|
|
10751
10999
|
try {
|
|
10752
11000
|
this.savedViews = await useSavedViewsApi().fetchViews()
|
|
11001
|
+
// An empty answer is also what a misread response gives, so it
|
|
11002
|
+
// never empties the menu: entries are dropped only against a
|
|
11003
|
+
// list that came back with views in it.
|
|
11004
|
+
if (this.savedViews.length > 0) {
|
|
11005
|
+
this.syncSavedViewMenu()
|
|
11006
|
+
}
|
|
11007
|
+
this.applySavedViewFromRoute()
|
|
10753
11008
|
} catch (error) {
|
|
10754
11009
|
// eslint-disable-next-line no-console
|
|
10755
11010
|
console.error('CnIndexPage: failed to fetch saved views', error)
|
|
@@ -10767,10 +11022,15 @@ export default {
|
|
|
10767
11022
|
* query implicitly resets `_page` to 1.
|
|
10768
11023
|
*
|
|
10769
11024
|
* @param {object} view The View API object to apply.
|
|
11025
|
+
* @param {{keepSavedViewKey?: boolean}} [options] Keep `?savedView=<id>` in the address, as a menu entry's link does.
|
|
10770
11026
|
*/
|
|
10771
|
-
onApplySavedView(view) {
|
|
11027
|
+
onApplySavedView(view, { keepSavedViewKey = false } = {}) {
|
|
10772
11028
|
this.appliedSavedViewId = view && (view.id || view.slug) ? String(view.id || view.slug) : ''
|
|
10773
11029
|
const state = extractViewState(view)
|
|
11030
|
+
if (view && view.seeded === true) {
|
|
11031
|
+
const ctx = typeof this.selfFetchTokenCtx === 'function' ? this.selfFetchTokenCtx() : {}
|
|
11032
|
+
state.filters = resolveFilterTokens(state.filters, ctx)
|
|
11033
|
+
}
|
|
10774
11034
|
// A view that carries columns wins while it is applied; one without leaves the person's own layout.
|
|
10775
11035
|
const viewColumns = view && view.query && Array.isArray(view.query.columns) ? view.query.columns.map(String) : []
|
|
10776
11036
|
this.appliedViewColumns = viewColumns.length > 0 ? viewColumns : null
|
|
@@ -10789,14 +11049,18 @@ export default {
|
|
|
10789
11049
|
// Through `persistViewStateToRoute` rather than a raw replace,
|
|
10790
11050
|
// because it is what records the keys this view wrote — without
|
|
10791
11051
|
// that, a later "clear all" has nothing to delete them by.
|
|
10792
|
-
this.persistViewStateToRoute(state)
|
|
11052
|
+
this.persistViewStateToRoute(state, { savedView: keepSavedViewKey ? this.appliedSavedViewId : '' })
|
|
10793
11053
|
this.$emit('apply-view', view)
|
|
10794
11054
|
return
|
|
10795
11055
|
}
|
|
10796
11056
|
if (!this.$router) {
|
|
10797
11057
|
return
|
|
10798
11058
|
}
|
|
10799
|
-
const
|
|
11059
|
+
const query = buildRouteQueryFromViewState(state)
|
|
11060
|
+
if (keepSavedViewKey) {
|
|
11061
|
+
query.savedView = this.appliedSavedViewId
|
|
11062
|
+
}
|
|
11063
|
+
const nav = this.$router.replace({ query })
|
|
10800
11064
|
// Swallow the duplicate-navigation rejection (Vue Router 3)
|
|
10801
11065
|
// when the applied view matches the current query.
|
|
10802
11066
|
if (nav && typeof nav.catch === 'function') {
|
|
@@ -10881,6 +11145,8 @@ export default {
|
|
|
10881
11145
|
}
|
|
10882
11146
|
this.savedViews = [...this.savedViews, view]
|
|
10883
11147
|
this.showSaveViewDialog = false
|
|
11148
|
+
this.sidebarActiveTab = 'filters-tab'
|
|
11149
|
+
this.sidebarOpen = true
|
|
10884
11150
|
this.toastSavedView('success', t('nextcloud-vue', 'View "{name}" saved', { name }))
|
|
10885
11151
|
} catch (error) {
|
|
10886
11152
|
// eslint-disable-next-line no-console
|
|
@@ -10930,6 +11196,125 @@ export default {
|
|
|
10930
11196
|
}
|
|
10931
11197
|
},
|
|
10932
11198
|
|
|
11199
|
+
/**
|
|
11200
|
+
* One saved-view intent from the sidebar's Search tab.
|
|
11201
|
+
*
|
|
11202
|
+
* @param {{action: string, view: (object|null)}} event The intent.
|
|
11203
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-6
|
|
11204
|
+
*/
|
|
11205
|
+
onSavedViewAction({ action, view } = {}) {
|
|
11206
|
+
const handlers = {
|
|
11207
|
+
apply: () => this.onApplySavedView(view),
|
|
11208
|
+
save: () => { this.showSaveViewDialog = true },
|
|
11209
|
+
edit: () => this.onEditViewRequest(view),
|
|
11210
|
+
share: () => this.onShareViewRequest(view),
|
|
11211
|
+
presentation: () => this.onPresentationViewRequest(view),
|
|
11212
|
+
update: () => this.onUpdateViewRequest(view),
|
|
11213
|
+
copy: () => this.onCopyViewRequest(view),
|
|
11214
|
+
menu: () => this.onToggleSavedViewInMenu(view),
|
|
11215
|
+
delete: () => this.onDeleteViewRequest(view),
|
|
11216
|
+
}
|
|
11217
|
+
if (handlers[action]) {
|
|
11218
|
+
handlers[action]()
|
|
11219
|
+
}
|
|
11220
|
+
},
|
|
11221
|
+
|
|
11222
|
+
/**
|
|
11223
|
+
* Add a saved view to the app menu, or take it out. Stored per user
|
|
11224
|
+
* by CnAppRoot; the view itself is not touched, so a view shared
|
|
11225
|
+
* with this user can be added as well as an own one.
|
|
11226
|
+
*
|
|
11227
|
+
* @param {object} view The view.
|
|
11228
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-7
|
|
11229
|
+
*/
|
|
11230
|
+
onToggleSavedViewInMenu(view) {
|
|
11231
|
+
const menu = this.cnSavedViewMenu
|
|
11232
|
+
if (!view || !menu || typeof menu.toggle !== 'function' || this.savedViewPage === '') {
|
|
11233
|
+
return
|
|
11234
|
+
}
|
|
11235
|
+
menu.toggle({ id: String(view.id || view.slug), page: this.savedViewPage, name: view.name })
|
|
11236
|
+
},
|
|
11237
|
+
|
|
11238
|
+
/**
|
|
11239
|
+
* Bring this page's menu entries in line with the views it can show:
|
|
11240
|
+
* current names, and none for a view deleted or no longer shared.
|
|
11241
|
+
*
|
|
11242
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-7
|
|
11243
|
+
*/
|
|
11244
|
+
syncSavedViewMenu() {
|
|
11245
|
+
const menu = this.cnSavedViewMenu
|
|
11246
|
+
if (!menu || typeof menu.sync !== 'function' || this.savedViewPage === '') {
|
|
11247
|
+
return
|
|
11248
|
+
}
|
|
11249
|
+
menu.sync(this.savedViewPage, [...this.defaultFilterViews, ...this.visibleSavedViews])
|
|
11250
|
+
},
|
|
11251
|
+
|
|
11252
|
+
/**
|
|
11253
|
+
* Apply the saved view the address names (`?savedView=<id>`, what a
|
|
11254
|
+
* menu entry links to), once the list holding it has loaded.
|
|
11255
|
+
*
|
|
11256
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-7
|
|
11257
|
+
*/
|
|
11258
|
+
applySavedViewFromRoute() {
|
|
11259
|
+
const id = this.$route && this.$route.query ? this.$route.query.savedView : undefined
|
|
11260
|
+
if (typeof id !== 'string' || id === '' || id === this.appliedSavedViewId) {
|
|
11261
|
+
return
|
|
11262
|
+
}
|
|
11263
|
+
const view = this.viewsForControl.find((v) => String(v.id) === id || String(v.slug) === id)
|
|
11264
|
+
if (view) {
|
|
11265
|
+
this.onApplySavedView(view, { keepSavedViewKey: true })
|
|
11266
|
+
}
|
|
11267
|
+
},
|
|
11268
|
+
|
|
11269
|
+
/**
|
|
11270
|
+
* Open the edit dialog for an own view (CnSavedViewsControl `@edit-request`).
|
|
11271
|
+
*
|
|
11272
|
+
* @param {object} view The View API object.
|
|
11273
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-3
|
|
11274
|
+
*/
|
|
11275
|
+
onEditViewRequest(view) {
|
|
11276
|
+
this.viewPendingEdit = view
|
|
11277
|
+
},
|
|
11278
|
+
|
|
11279
|
+
/**
|
|
11280
|
+
* Save a rename, and the current filters when asked
|
|
11281
|
+
* (CnSavedViewEditDialog `@confirm`). The PATCH carries `name`, plus
|
|
11282
|
+
* `query` only when the criteria are replaced, so nothing else on the
|
|
11283
|
+
* view is rewritten from this tab's copy. A refusal keeps the dialog open.
|
|
11284
|
+
*
|
|
11285
|
+
* @param {{ name: string, replaceCriteria: boolean }} payload The dialog payload.
|
|
11286
|
+
* @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-3
|
|
11287
|
+
*/
|
|
11288
|
+
async onEditViewConfirm({ name, replaceCriteria }) {
|
|
11289
|
+
const view = this.viewPendingEdit
|
|
11290
|
+
if (!view) {
|
|
11291
|
+
return
|
|
11292
|
+
}
|
|
11293
|
+
const body = { name }
|
|
11294
|
+
if (replaceCriteria === true) {
|
|
11295
|
+
const state = this.isSelfFetchMode
|
|
11296
|
+
? this.currentViewState()
|
|
11297
|
+
: extractViewStateFromRouteQuery((this.$route && this.$route.query) || {})
|
|
11298
|
+
body.query = buildViewCreatePayload({
|
|
11299
|
+
name,
|
|
11300
|
+
state,
|
|
11301
|
+
scope: savedViewScope(this.savedViewsPage),
|
|
11302
|
+
register: this.register,
|
|
11303
|
+
schema: this.schema,
|
|
11304
|
+
}).query
|
|
11305
|
+
}
|
|
11306
|
+
try {
|
|
11307
|
+
const saved = await useSavedViewsApi().patchView(view.id, body)
|
|
11308
|
+
this.savedViews = this.savedViews.map((v) => (v.id === view.id ? { ...v, ...(saved || body) } : v))
|
|
11309
|
+
this.syncSavedViewMenu()
|
|
11310
|
+
this.viewPendingEdit = null
|
|
11311
|
+
this.toastSavedView('success', t('nextcloud-vue', 'View "{name}" saved', { name }))
|
|
11312
|
+
} catch (error) {
|
|
11313
|
+
const data = error?.response?.data
|
|
11314
|
+
this.$refs.editViewDialog?.setError((data && (data.error || data.message)) || error?.message)
|
|
11315
|
+
}
|
|
11316
|
+
},
|
|
11317
|
+
|
|
10933
11318
|
/**
|
|
10934
11319
|
* Open the share dialog for an own view (CnSavedViewsControl `@share-request`).
|
|
10935
11320
|
*
|
|
@@ -11048,6 +11433,7 @@ export default {
|
|
|
11048
11433
|
try {
|
|
11049
11434
|
await useSavedViewsApi().deleteView(view.id)
|
|
11050
11435
|
this.savedViews = this.savedViews.filter((v) => v.id !== view.id)
|
|
11436
|
+
this.syncSavedViewMenu()
|
|
11051
11437
|
this.$refs.deleteViewConfirmDialog?.setResult({ success: true })
|
|
11052
11438
|
} catch (error) {
|
|
11053
11439
|
// eslint-disable-next-line no-console
|