@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.
Files changed (135) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +9 -0
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js.map +1 -0
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +338 -0
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -0
  5. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +249 -0
  6. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -0
  7. package/dist/esm/components/CnAdvancedFormDialog/CnPropertiesTab.vue2.js +2 -2
  8. package/dist/esm/components/CnAdvancedFormDialog/CnPropertiesTab.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  10. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +145 -138
  11. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  12. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +102 -2
  13. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  14. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  15. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  16. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +83 -6
  17. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  18. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +4 -2
  19. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  20. package/dist/esm/components/CnIcon/semanticIcons.js +2 -2
  21. package/dist/esm/components/CnIcon/semanticIcons.js.map +1 -1
  22. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +389 -20
  23. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  24. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +68 -35
  25. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  26. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +22 -2
  27. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  28. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +69 -5
  29. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  30. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +38 -5
  31. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  32. package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
  33. package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +7 -1
  34. package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
  35. package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
  36. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js +8 -0
  37. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js.map +1 -0
  38. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js +297 -0
  39. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js.map +1 -0
  40. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js +24 -0
  41. package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js.map +1 -0
  42. package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue.js +9 -0
  43. package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue.js.map +1 -0
  44. package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue2.js +95 -0
  45. package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue2.js.map +1 -0
  46. package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue3.js +123 -0
  47. package/dist/esm/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue3.js.map +1 -0
  48. package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue.js +1 -1
  49. package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue2.js +13 -5
  50. package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue2.js.map +1 -1
  51. package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue3.js +3 -1
  52. package/dist/esm/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue3.js.map +1 -1
  53. package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue.js +1 -1
  54. package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue2.js +49 -23
  55. package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue2.js.map +1 -1
  56. package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue3.js +74 -27
  57. package/dist/esm/components/CnSavedViewShareFields/CnSavedViewShareFields.vue3.js.map +1 -1
  58. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue.js +0 -1
  59. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue.js.map +1 -1
  60. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +18 -413
  61. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
  62. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js +27 -214
  63. package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
  64. package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue.js +9 -0
  65. package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue.js.map +1 -0
  66. package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue2.js +190 -0
  67. package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue2.js.map +1 -0
  68. package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue3.js +270 -0
  69. package/dist/esm/components/CnSavedViewsPanel/CnSavedViewsPanel.vue3.js.map +1 -0
  70. package/dist/esm/index.js +4 -0
  71. package/dist/esm/index.js.map +1 -1
  72. package/dist/esm/l10n/en.json.js +56 -1
  73. package/dist/esm/l10n/en.json.js.map +1 -1
  74. package/dist/esm/l10n/nl.json.js +56 -1
  75. package/dist/esm/l10n/nl.json.js.map +1 -1
  76. package/dist/esm/library-style.js +1 -1
  77. package/dist/esm/mixins/savedViewsList.js +235 -0
  78. package/dist/esm/mixins/savedViewsList.js.map +1 -0
  79. package/dist/esm/nextcloud-vue.css +348 -108
  80. package/dist/esm/utils/actionsDispatcher.js +2 -2
  81. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  82. package/dist/esm/utils/builtInModals.js +39 -0
  83. package/dist/esm/utils/builtInModals.js.map +1 -0
  84. package/dist/esm/utils/mapMarkerColor.js +121 -0
  85. package/dist/esm/utils/mapMarkerColor.js.map +1 -0
  86. package/dist/esm/utils/mergeManifestDelta.js +4 -0
  87. package/dist/esm/utils/mergeManifestDelta.js.map +1 -1
  88. package/dist/esm/utils/savedViewHelpers.js +59 -7
  89. package/dist/esm/utils/savedViewHelpers.js.map +1 -1
  90. package/dist/esm/utils/savedViewMenu.js +154 -0
  91. package/dist/esm/utils/savedViewMenu.js.map +1 -0
  92. package/dist/esm/utils/searchGroupSharees.js +50 -15
  93. package/dist/esm/utils/searchGroupSharees.js.map +1 -1
  94. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  95. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  96. package/dist/nextcloud-vue.cjs.js +13351 -10855
  97. package/dist/nextcloud-vue.cjs.js.map +2 -2
  98. package/dist/nextcloud-vue.css +348 -108
  99. package/l10n/en.json +56 -1
  100. package/l10n/nl.json +56 -1
  101. package/package.json +1 -1
  102. package/src/components/CnActionDialog/CnActionDialog.vue +545 -0
  103. package/src/components/CnActionDialog/index.js +12 -0
  104. package/src/components/CnAppNav/CnAppNav.vue +17 -0
  105. package/src/components/CnAppRoot/CnAppRoot.vue +102 -2
  106. package/src/components/CnDashboardPage/CnDashboardPage.vue +86 -7
  107. package/src/components/CnIndexPage/CnIndexPage.vue +409 -23
  108. package/src/components/CnIndexPage/useSelfFetchList.js +21 -1
  109. package/src/components/CnIndexSidebar/CnIndexSidebar.md +2 -0
  110. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +91 -1
  111. package/src/components/CnMapWidget/CnMapWidget.vue +16 -1
  112. package/src/components/CnPartyPicker/CnPartyPicker.vue +317 -0
  113. package/src/components/CnPartyPicker/index.js +11 -0
  114. package/src/components/CnSavedViewEditDialog/CnSavedViewEditDialog.vue +192 -0
  115. package/src/components/CnSavedViewEditDialog/index.js +11 -0
  116. package/src/components/CnSavedViewShareDialog/CnSavedViewShareDialog.vue +21 -6
  117. package/src/components/CnSavedViewShareFields/CnSavedViewShareFields.vue +130 -37
  118. package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +36 -599
  119. package/src/components/CnSavedViewsPanel/CnSavedViewsPanel.vue +459 -0
  120. package/src/components/CnSavedViewsPanel/index.js +11 -0
  121. package/src/components/index.js +4 -0
  122. package/src/css/index-page.css +16 -0
  123. package/src/css/look-board-index.css +5 -3
  124. package/src/css/look-board.css +18 -3
  125. package/src/index.js +4 -0
  126. package/src/mixins/savedViewsList.js +231 -0
  127. package/src/schemas/app-manifest-v2.schema.json +98 -3
  128. package/src/utils/actionsDispatcher.js +2 -2
  129. package/src/utils/builtInModals.js +35 -0
  130. package/src/utils/mapMarkerColor.js +117 -0
  131. package/src/utils/mergeManifestDelta.js +4 -0
  132. package/src/utils/savedViewHelpers.js +58 -6
  133. package/src/utils/savedViewMenu.js +150 -0
  134. package/src/utils/searchGroupSharees.js +49 -14
  135. 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`): lists the user's
327
- OpenRegister saved-search views; applying one writes its stored
328
- filters/search/sort into the route query. -->
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
- return t('nextcloud-vue', 'Delete the view "{name}"? This cannot be undone.', { name: this.viewPendingDelete.name })
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 (previous === 'calendar' || previous === 'board') {
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 nav = this.$router.replace({ query: buildRouteQueryFromViewState(state) })
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