@conduction/nextcloud-vue 2.56.0-beta.11 → 2.56.0-beta.13

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 (138) hide show
  1. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +253 -10
  2. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +139 -46
  4. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +87 -0
  6. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  7. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +26 -24
  8. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +61 -16
  10. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  11. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  12. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +20 -0
  13. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
  14. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +3 -2
  15. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
  16. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +13 -0
  17. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
  18. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +2 -1
  19. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
  20. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -2
  21. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  22. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  23. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +154 -4
  24. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  25. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +555 -480
  26. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  27. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js +9 -3
  28. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js.map +1 -1
  29. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js +1 -1
  30. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js.map +1 -1
  31. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +37 -1
  32. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  33. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +12 -4
  34. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  35. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +187 -19
  36. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  37. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +215 -135
  38. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  39. package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js +3 -1
  40. package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +144 -4
  42. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  43. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  44. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +157 -7
  45. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  46. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +23 -5
  47. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  48. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -0
  49. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  50. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -2
  51. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  52. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +5 -1
  53. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  54. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  55. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  56. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +11 -0
  57. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
  58. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +2 -1
  59. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
  60. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +63 -2
  61. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  62. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +96 -37
  63. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  64. package/dist/esm/components/CnStagesWidget/stagesModel.js +5 -2
  65. package/dist/esm/components/CnStagesWidget/stagesModel.js.map +1 -1
  66. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +74 -5
  67. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  68. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +15 -8
  69. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  70. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +14 -2
  71. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  72. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +2 -1
  73. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  74. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +73 -1
  75. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
  76. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +14 -2
  77. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
  78. package/dist/esm/l10n/en.json.js +5 -1
  79. package/dist/esm/l10n/en.json.js.map +1 -1
  80. package/dist/esm/l10n/nl.json.js +5 -1
  81. package/dist/esm/l10n/nl.json.js.map +1 -1
  82. package/dist/esm/mixins/pageViews.js +400 -0
  83. package/dist/esm/mixins/pageViews.js.map +1 -0
  84. package/dist/esm/nextcloud-vue.css +513 -81
  85. package/dist/esm/store/useObjectStore.js +118 -33
  86. package/dist/esm/store/useObjectStore.js.map +1 -1
  87. package/dist/esm/utils/actionsDispatcher.js +25 -2
  88. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  89. package/dist/esm/utils/columnFilters.js +27 -3
  90. package/dist/esm/utils/columnFilters.js.map +1 -1
  91. package/dist/esm/utils/schema.js +40 -2
  92. package/dist/esm/utils/schema.js.map +1 -1
  93. package/dist/esm/utils/schemaRefSlug.js +19 -3
  94. package/dist/esm/utils/schemaRefSlug.js.map +1 -1
  95. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  96. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  97. package/dist/nextcloud-vue.cjs.js +8858 -6566
  98. package/dist/nextcloud-vue.cjs.js.map +2 -2
  99. package/dist/nextcloud-vue.css +513 -81
  100. package/l10n/en.json +5 -0
  101. package/l10n/nl.json +5 -0
  102. package/package.json +1 -1
  103. package/src/components/CnAppNav/CnAppNav.vue +441 -14
  104. package/src/components/CnAppRoot/CnAppRoot.md +4 -0
  105. package/src/components/CnAppRoot/CnAppRoot.vue +94 -1
  106. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +61 -16
  107. package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +22 -1
  108. package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +14 -0
  109. package/src/components/CnCellRenderer/CnCellRenderer.vue +33 -2
  110. package/src/components/CnDashboardPage/CnDashboardPage.vue +237 -12
  111. package/src/components/CnDataTable/CnColumnFilterPopover.vue +11 -5
  112. package/src/components/CnDataTable/CnDataTable.vue +45 -1
  113. package/src/components/CnDetailPage/CnDetailPage.md +8 -0
  114. package/src/components/CnDetailPage/CnDetailPage.vue +263 -7
  115. package/src/components/CnFkResolveCell/CnFkResolveCell.vue +3 -1
  116. package/src/components/CnFormDialog/CnFormDialog.vue +144 -4
  117. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +206 -9
  118. package/src/components/CnIndexPage/CnIndexPage.vue +32 -2
  119. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +7 -1
  120. package/src/components/CnSegmentedControl/CnSegmentedControl.md +1 -1
  121. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +12 -0
  122. package/src/components/CnStagesWidget/CnStagesWidget.vue +189 -2
  123. package/src/components/CnStagesWidget/stagesModel.js +5 -2
  124. package/src/components/CnStatWidget/CnStatWidget.vue +89 -7
  125. package/src/components/CnTabsWidget/CnTabsWidget.vue +15 -2
  126. package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +4 -0
  127. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +107 -1
  128. package/src/css/detail-page.css +37 -4
  129. package/src/css/kpi-card.css +71 -1
  130. package/src/css/table.css +18 -6
  131. package/src/mixins/pageViews.js +396 -0
  132. package/src/schemas/app-manifest-v2.schema.json +162 -3
  133. package/src/store/useObjectStore.js +118 -33
  134. package/src/utils/actionsDispatcher.js +25 -2
  135. package/src/utils/columnFilters.js +29 -2
  136. package/src/utils/schema.js +40 -2
  137. package/src/utils/schemaRefSlug.js +19 -3
  138. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -13,6 +13,7 @@ import __sfc_main$b from '../CnBuildiqEditButton/CnBuildiqEditButton.vue.js';
13
13
  import __sfc_main$4 from '../CnChartWidget/CnChartWidget.vue.js';
14
14
  import __sfc_main from '../CnDashboardGrid/CnDashboardGrid.vue.js';
15
15
  import __sfc_main$8 from '../CnDateRangePicker/CnDateRangePicker.vue.js';
16
+ import __sfc_main$e from '../CnSegmentedControl/CnSegmentedControl.vue.js';
16
17
  import __sfc_main$5 from '../CnStatsBlockWidget/CnStatsBlockWidget.vue.js';
17
18
  import __sfc_main$3 from '../CnTileWidget/CnTileWidget.vue.js';
18
19
  import __sfc_main$6 from '../CnWidgetRefItem/CnWidgetRefItem.vue.js';
@@ -20,6 +21,7 @@ import __sfc_main$2 from '../CnWidgetRenderer/CnWidgetRenderer.vue.js';
20
21
  import __sfc_main$1 from '../CnWidgetWrapper/CnWidgetWrapper.vue.js';
21
22
  import { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js';
22
23
  import { readUserPreference, writeUserPreference } from '../../composables/useUserPreferences.js';
24
+ import { pageViews } from '../../mixins/pageViews.js';
23
25
  import { mergeUserLayout, dashboardLayoutKey } from '../../store/plugins/dashboardLayouts.js';
24
26
  import { isAppInstalled } from '../../utils/appInstalled.js';
25
27
  import { readVisibleWhenValue, compareVisibleWhen } from '../../utils/visibleWhen.js';
@@ -175,8 +177,11 @@ var script = {
175
177
  CnBuildiqEditButton: __sfc_main$b,
176
178
  CnWidgetStyleEditorModal: __sfc_main$c,
177
179
  CnLeafMountHost: __sfc_main$d,
180
+ CnSegmentedControl: __sfc_main$e,
178
181
  },
179
182
 
183
+ mixins: [pageViews],
184
+
180
185
  inject: {
181
186
  /**
182
187
  * Buildiq in-app edit state (ADR-041), provided by CnAppRoot as a ref.
@@ -236,6 +241,34 @@ var script = {
236
241
  default: '',
237
242
  },
238
243
 
244
+ /**
245
+ * Whether the header row renders: title, description, header actions
246
+ * and the edit toggle. `false` (manifest `config.showHeader: false`)
247
+ * drops it for a page whose first widget is its heading; the title
248
+ * then renders visually hidden so the page keeps an accessible name.
249
+ *
250
+ * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-dashboard-page-can-hide-its-header
251
+ */
252
+ showHeader: {
253
+ type: Boolean,
254
+ default: true,
255
+ },
256
+
257
+ /**
258
+ * Whether a widget draws its overflow Actions menu when neither its
259
+ * placement nor its definition says (`showActions`). `false` (manifest
260
+ * `config.showWidgetActions: false`) drops the menu from every such
261
+ * widget, for a dashboard whose widgets carry a header link and
262
+ * nothing else. A widget that sets `showActions: true` keeps its menu.
263
+ * Card widgets have no menu either way.
264
+ *
265
+ * @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-dashboard-can-drop-the-widget-actions-menu
266
+ */
267
+ showWidgetActions: {
268
+ type: Boolean,
269
+ default: true,
270
+ },
271
+
239
272
  /**
240
273
  * Widget definitions array. Each widget defines metadata for rendering.
241
274
  *
@@ -1151,6 +1184,89 @@ var script = {
1151
1184
  return this.layout.length > 0 || this.widgetRefItems.length > 0
1152
1185
  },
1153
1186
 
1187
+ /**
1188
+ * Whether the grid sections render at all: not while loading, not
1189
+ * while the widget predicates settle, not on the empty page and not
1190
+ * on a widget-ref content page.
1191
+ *
1192
+ * @return {boolean}
1193
+ * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid
1194
+ */
1195
+ gridSectionsShown() {
1196
+ if (this.loading || (!this.widgetConditionsSettled && !this.gridEditable)) {
1197
+ return false
1198
+ }
1199
+ if (!this.hasWidgets && !this.hasBodyWidgets && !this.hasViews) {
1200
+ return false
1201
+ }
1202
+ return this.widgetRefItems.length === 0
1203
+ },
1204
+
1205
+ /**
1206
+ * The chosen view's layout as the grid draws it: in live mode the
1207
+ * widgets that would draw nothing leave and the rest close up, as
1208
+ * for the page's own layout.
1209
+ *
1210
+ * @return {Array<object>}
1211
+ * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so
1212
+ */
1213
+ viewDisplayLayout() {
1214
+ const items = this.activeView ? this.activeView.layout : [];
1215
+ if (this.gridEditable) {
1216
+ return items
1217
+ }
1218
+ const visible = items.filter((item) => !this.isCollapsedWidget(item));
1219
+ return visible.length === items.length ? items : this.compactDisplayLayout(visible)
1220
+ },
1221
+
1222
+ /**
1223
+ * Whether the chosen view has nothing to draw.
1224
+ *
1225
+ * @return {boolean}
1226
+ * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so
1227
+ */
1228
+ viewIsEmpty() {
1229
+ return this.hasViews && this.viewDisplayLayout.length === 0
1230
+ },
1231
+
1232
+ /**
1233
+ * The grids this page draws. Without views: the page's own layout,
1234
+ * as it always was. With views: the page's own layout when it has
1235
+ * items, then the chosen view's layout in the region the switch
1236
+ * controls (left out when the view is empty; the empty state takes
1237
+ * the region then).
1238
+ *
1239
+ * @return {Array<{key: string, view: boolean, layout: Array<object>, editable: boolean, attrs: object}>}
1240
+ * @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid
1241
+ */
1242
+ gridSections() {
1243
+ if (!this.gridSectionsShown) {
1244
+ return []
1245
+ }
1246
+ const page = { key: 'page', view: false, layout: this.displayLayout, editable: this.gridEditable, attrs: {} };
1247
+ if (!this.hasViews) {
1248
+ return [page]
1249
+ }
1250
+ const sections = this.displayLayout.length > 0 ? [page] : [];
1251
+ if (!this.viewIsEmpty) {
1252
+ sections.push({
1253
+ key: `view-${this.activeViewId}`,
1254
+ view: true,
1255
+ layout: this.viewDisplayLayout,
1256
+ // A user arrangement covers the page's own layout only.
1257
+ editable: this.gridEditable && !this.userLayout,
1258
+ attrs: {
1259
+ id: this.viewRegionId,
1260
+ role: 'region',
1261
+ 'aria-label': this.activeView.label,
1262
+ class: 'cn-page-view-region',
1263
+ 'data-testid': 'cn-dashboard-page-view-region',
1264
+ },
1265
+ });
1266
+ }
1267
+ return sections
1268
+ },
1269
+
1154
1270
  /**
1155
1271
  * The widget settings object handed to CnWidgetStyleEditorModal,
1156
1272
  * built from the widget definition currently being configured
@@ -1281,6 +1397,14 @@ var script = {
1281
1397
  this.evaluateWidgetConditions();
1282
1398
  },
1283
1399
  },
1400
+
1401
+ /** A view's widgets carry predicates too. */
1402
+ views: {
1403
+ deep: true,
1404
+ handler() {
1405
+ this.evaluateWidgetConditions();
1406
+ },
1407
+ },
1284
1408
  },
1285
1409
 
1286
1410
  created() {
@@ -2145,7 +2269,8 @@ var script = {
2145
2269
  * @spec openspec/changes/live-check-follow-ups/specs/live-check-follow-ups/spec.md#requirement-an-attention-card-says-when-it-could-not-check
2146
2270
  */
2147
2271
  async evaluateWidgetConditions() {
2148
- const conditional = (this.widgets || []).filter((def) => def && def.id && def.type
2272
+ const defs = [...(this.widgets || []), ...this.normalizedViews.flatMap((view) => view.widgets)];
2273
+ const conditional = defs.filter((def) => def && def.id && def.type
2149
2274
  && this.widgetDisplayConfig(def).visibleWhen);
2150
2275
  // Skip when the CONDITIONAL SET is unchanged: the deep `widgets`
2151
2276
  // watch fires on any def edit, but only an added/removed/edited
@@ -2279,7 +2404,7 @@ var script = {
2279
2404
  */
2280
2405
  getWidgetDef(widgetId) {
2281
2406
  const list = Array.isArray(this.widgets) ? this.widgets : [];
2282
- return list.find((w) => w && w.id === widgetId) || null
2407
+ return list.find((w) => w && w.id === widgetId) || this.findViewWidget(widgetId)
2283
2408
  },
2284
2409
 
2285
2410
  /**
@@ -2670,11 +2795,20 @@ var script = {
2670
2795
  * exactly that reason; there is now one rule for every family, so a
2671
2796
  * custom slot and a registered widget cannot disagree about it.
2672
2797
  *
2798
+ * A greeting header that declares `content.ground: true` sits on the
2799
+ * page ground, so it asks for no card either: one key on the widget
2800
+ * instead of a second one on its placement.
2801
+ *
2802
+ * @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-greeting-can-sit-on-the-page-ground
2673
2803
  * @param {object} item the layout placement.
2674
2804
  * @return {boolean}
2675
2805
  */
2676
2806
  widgetBorderless(item) {
2677
- return item.borderless === true
2807
+ if (item.borderless === true) {
2808
+ return true
2809
+ }
2810
+ const def = this.getWidgetDef(item.widgetId);
2811
+ return Boolean(def && def.type === 'header' && this.getWidgetContent(item).ground === true)
2678
2812
  },
2679
2813
 
2680
2814
  /**
@@ -2691,7 +2825,7 @@ var script = {
2691
2825
  const def = this.getWidgetDef(item.widgetId);
2692
2826
  const value = item.showActions !== undefined ? item.showActions : def?.showActions;
2693
2827
  if (value === undefined || value === null) {
2694
- return !this.isCardWidget(item)
2828
+ return this.showWidgetActions && !this.isCardWidget(item)
2695
2829
  }
2696
2830
  return value !== false
2697
2831
  },
@@ -2725,6 +2859,22 @@ var script = {
2725
2859
  return def?.buttons || []
2726
2860
  },
2727
2861
 
2862
+ /**
2863
+ * The widget's header text link (`headerLink` on the layout entry,
2864
+ * else on the widget definition), forwarded to CnWidgetWrapper.
2865
+ *
2866
+ * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-widget-header-carries-a-text-link
2867
+ * @param {object} item Layout placement entry.
2868
+ * @return {object|null}
2869
+ */
2870
+ getWidgetHeaderLink(item) {
2871
+ if (item?.headerLink && typeof item.headerLink === 'object') {
2872
+ return item.headerLink
2873
+ }
2874
+ const def = this.getWidgetDef(item.widgetId);
2875
+ return (def?.headerLink && typeof def.headerLink === 'object') ? def.headerLink : null
2876
+ },
2877
+
2728
2878
  /**
2729
2879
  * Whether a widget's overflow Actions menu shows the Refresh item.
2730
2880
  * An explicit per-widget flag wins — on the widget definition or