@conduction/nextcloud-vue 2.56.0-beta.12 → 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.
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +99 -3
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +23 -7
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +13 -0
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +2 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +125 -4
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +439 -381
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js +9 -3
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js +1 -1
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +142 -26
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +195 -124
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js +3 -1
- package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +144 -4
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +84 -11
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +3 -2
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +11 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +2 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +22 -3
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +10 -3
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +3 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +3 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/mixins/pageViews.js +400 -0
- package/dist/esm/mixins/pageViews.js.map +1 -0
- package/dist/esm/nextcloud-vue.css +182 -0
- package/dist/esm/store/useObjectStore.js +118 -33
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/actionsDispatcher.js +25 -2
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/esm/utils/columnFilters.js +27 -3
- package/dist/esm/utils/columnFilters.js.map +1 -1
- package/dist/esm/utils/schema.js +40 -2
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +2001 -684
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +182 -0
- package/l10n/en.json +3 -0
- package/l10n/nl.json +3 -0
- package/package.json +1 -1
- package/src/components/CnAppNav/CnAppNav.vue +148 -7
- package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +14 -0
- package/src/components/CnDashboardPage/CnDashboardPage.vue +194 -10
- package/src/components/CnDataTable/CnColumnFilterPopover.vue +11 -5
- package/src/components/CnDetailPage/CnDetailPage.md +5 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +208 -11
- package/src/components/CnFkResolveCell/CnFkResolveCell.vue +3 -1
- package/src/components/CnFormDialog/CnFormDialog.vue +144 -4
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +100 -13
- package/src/components/CnSegmentedControl/CnSegmentedControl.md +1 -1
- package/src/components/CnSegmentedControl/CnSegmentedControl.vue +12 -0
- package/src/components/CnStagesWidget/CnStagesWidget.vue +9 -0
- package/src/components/CnStatWidget/CnStatWidget.vue +33 -5
- package/src/css/detail-page.css +27 -0
- package/src/css/kpi-card.css +47 -0
- package/src/mixins/pageViews.js +396 -0
- package/src/schemas/app-manifest-v2.schema.json +51 -2
- package/src/store/useObjectStore.js +118 -33
- package/src/utils/actionsDispatcher.js +25 -2
- package/src/utils/columnFilters.js +29 -2
- package/src/utils/schema.js +40 -2
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -32,6 +32,18 @@
|
|
|
32
32
|
</p>
|
|
33
33
|
</div>
|
|
34
34
|
<div class="cn-dashboard-page__header-actions">
|
|
35
|
+
<!-- The page's view switch (`views`), unless a greeting header
|
|
36
|
+
widget on the page draws it. Its options control the view
|
|
37
|
+
region below the grid. -->
|
|
38
|
+
<CnSegmentedControl
|
|
39
|
+
v-if="showsPageViewSwitch"
|
|
40
|
+
class="cn-page-view-switch"
|
|
41
|
+
:options="viewSwitchOptions"
|
|
42
|
+
:modelValue="activeViewId"
|
|
43
|
+
:ariaLabel="viewSwitchLabel"
|
|
44
|
+
:controls="viewRegionId"
|
|
45
|
+
data-testid="cn-dashboard-page-view-switch"
|
|
46
|
+
@update:modelValue="selectView" />
|
|
35
47
|
<!-- Declarative header actions (#91 Wave 3): a manifest
|
|
36
48
|
`headerActions[]` renders as buttons (open-form / api-call /
|
|
37
49
|
toggle / navigate / refresh) with visibleWhen gating,
|
|
@@ -218,7 +230,7 @@
|
|
|
218
230
|
sections (before-grid / after-grid / end): a page can legitimately
|
|
219
231
|
have no grid widgets yet still show bodyWidget content, so
|
|
220
232
|
"No widgets configured" would be a false negative. -->
|
|
221
|
-
<div v-else-if="!hasWidgets && !hasBodyWidgets" class="cn-dashboard-page__empty">
|
|
233
|
+
<div v-else-if="!hasWidgets && !hasBodyWidgets && !hasViews" class="cn-dashboard-page__empty">
|
|
222
234
|
<!-- @slot empty Replaces the default empty state shown when the dashboard has no widgets. Defaults to an `NcEmptyContent` block. -->
|
|
223
235
|
<slot name="empty">
|
|
224
236
|
<NcEmptyContent :description="emptyLabel">
|
|
@@ -253,15 +265,34 @@
|
|
|
253
265
|
to the layout/widgets arrays — in-place pushes (Add widget) keep
|
|
254
266
|
the same array identity and can't re-render it. One remount per
|
|
255
267
|
edit flip re-subscribes against the now-reactive graph. -->
|
|
268
|
+
<!-- The view switch for a page without a header row, when no greeting
|
|
269
|
+
header widget draws it. -->
|
|
270
|
+
<div
|
|
271
|
+
v-if="gridSectionsShown && !showHeader && showsPageViewSwitch"
|
|
272
|
+
class="cn-dashboard-page__view-switch">
|
|
273
|
+
<CnSegmentedControl
|
|
274
|
+
class="cn-page-view-switch"
|
|
275
|
+
:options="viewSwitchOptions"
|
|
276
|
+
:modelValue="activeViewId"
|
|
277
|
+
:ariaLabel="viewSwitchLabel"
|
|
278
|
+
:controls="viewRegionId"
|
|
279
|
+
data-testid="cn-dashboard-page-view-switch"
|
|
280
|
+
@update:modelValue="selectView" />
|
|
281
|
+
</div>
|
|
282
|
+
<!-- One grid per section: the page's own layout, then the chosen
|
|
283
|
+
view (`views`) in a region the view switch controls. Both are the
|
|
284
|
+
same grid with the same widget rendering below. A view grid is
|
|
285
|
+
keyed on its view, so switching mounts the other view's grid. -->
|
|
256
286
|
<CnDashboardGrid
|
|
257
|
-
v-
|
|
258
|
-
:key="`cn-dashboard-grid-${gridEditable ? 'editing' : 'live'}`"
|
|
259
|
-
|
|
260
|
-
:
|
|
287
|
+
v-for="section in gridSections"
|
|
288
|
+
:key="`cn-dashboard-grid-${section.key}-${gridEditable ? 'editing' : 'live'}`"
|
|
289
|
+
v-bind="section.attrs"
|
|
290
|
+
:layout="section.layout"
|
|
291
|
+
:editable="section.editable"
|
|
261
292
|
:columns="columns"
|
|
262
293
|
:cellHeight="cellHeight"
|
|
263
294
|
:margin="gridMargin"
|
|
264
|
-
@layoutChange="onLayoutChange">
|
|
295
|
+
@layoutChange="section.view ? onViewLayoutChange($event) : onLayoutChange($event)">
|
|
265
296
|
<template #widget="{ item }">
|
|
266
297
|
<!-- In-app edit overlay (ADR-041): a single launchpad-style
|
|
267
298
|
configure cog opens the per-widget style/config editor,
|
|
@@ -404,6 +435,7 @@
|
|
|
404
435
|
:iconUrl="getWidgetIconUrl(item)"
|
|
405
436
|
:iconClass="getWidgetIconClass(item)"
|
|
406
437
|
:showTitle="widgetShowTitle(item)"
|
|
438
|
+
:showActions="widgetShowActions(item)"
|
|
407
439
|
:borderless="widgetBorderless(item)"
|
|
408
440
|
:flush="item.flush !== false"
|
|
409
441
|
:buttons="getWidgetButtons(item)"
|
|
@@ -508,6 +540,7 @@
|
|
|
508
540
|
:iconUrl="getWidgetIconUrl(item)"
|
|
509
541
|
:iconClass="getWidgetIconClass(item)"
|
|
510
542
|
:showTitle="widgetShowTitle(item)"
|
|
543
|
+
:showActions="widgetShowActions(item)"
|
|
511
544
|
:borderless="widgetBorderless(item)"
|
|
512
545
|
:flush="item.flush !== false"
|
|
513
546
|
:buttons="getWidgetButtons(item)"
|
|
@@ -546,6 +579,7 @@
|
|
|
546
579
|
:iconUrl="getWidgetIconUrl(item)"
|
|
547
580
|
:iconClass="getWidgetIconClass(item)"
|
|
548
581
|
:showTitle="widgetShowTitle(item)"
|
|
582
|
+
:showActions="widgetShowActions(item)"
|
|
549
583
|
:buttons="getWidgetButtons(item)"
|
|
550
584
|
:headerLink="getWidgetHeaderLink(item)"
|
|
551
585
|
:styleConfig="item.styleConfig || {}"
|
|
@@ -652,6 +686,22 @@
|
|
|
652
686
|
</template>
|
|
653
687
|
</CnDashboardGrid>
|
|
654
688
|
|
|
689
|
+
<!-- The chosen view has nothing to draw: say so in the region, never
|
|
690
|
+
leave a blank area under the switch. -->
|
|
691
|
+
<div
|
|
692
|
+
v-if="gridSectionsShown && viewIsEmpty"
|
|
693
|
+
:id="viewRegionId"
|
|
694
|
+
role="region"
|
|
695
|
+
:aria-label="activeView ? activeView.label : null"
|
|
696
|
+
class="cn-page-view-region cn-page-view-region--empty"
|
|
697
|
+
data-testid="cn-dashboard-page-view-empty">
|
|
698
|
+
<NcEmptyContent :description="viewEmptyText">
|
|
699
|
+
<template #icon>
|
|
700
|
+
<ViewDashboardOutline :size="48" />
|
|
701
|
+
</template>
|
|
702
|
+
</NcEmptyContent>
|
|
703
|
+
</div>
|
|
704
|
+
|
|
655
705
|
<!-- Declarative in-body sections, `placement: "after-grid"` — host-app
|
|
656
706
|
section components rendered BELOW the widget grid. -->
|
|
657
707
|
<CnBodySections
|
|
@@ -711,6 +761,7 @@ import CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'
|
|
|
711
761
|
import CnChartWidget from '../CnChartWidget/CnChartWidget.vue'
|
|
712
762
|
import CnDashboardGrid from '../CnDashboardGrid/CnDashboardGrid.vue'
|
|
713
763
|
import CnDateRangePicker, { DEFAULT_DATE_RANGE_PRESETS, resolvePresetWindow } from '../CnDateRangePicker/CnDateRangePicker.vue'
|
|
764
|
+
import CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'
|
|
714
765
|
import CnStatsBlockWidget from '../CnStatsBlockWidget/CnStatsBlockWidget.vue'
|
|
715
766
|
import CnTileWidget from '../CnTileWidget/CnTileWidget.vue'
|
|
716
767
|
import CnWidgetRefItem from '../CnWidgetRefItem/CnWidgetRefItem.vue'
|
|
@@ -718,6 +769,7 @@ import CnWidgetRenderer from '../CnWidgetRenderer/CnWidgetRenderer.vue'
|
|
|
718
769
|
import CnWidgetWrapper from '../CnWidgetWrapper/CnWidgetWrapper.vue'
|
|
719
770
|
import { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js'
|
|
720
771
|
import { readUserPreference, writeUserPreference } from '../../composables/useUserPreferences.js'
|
|
772
|
+
import { pageViews } from '../../mixins/pageViews.js'
|
|
721
773
|
import { dashboardLayoutKey, mergeUserLayout } from '../../store/plugins/dashboardLayouts.js'
|
|
722
774
|
import { isAppInstalled } from '../../utils/appInstalled.js'
|
|
723
775
|
import { compareVisibleWhen, readVisibleWhenValue } from '../../utils/visibleWhen.js'
|
|
@@ -872,8 +924,11 @@ export default {
|
|
|
872
924
|
CnBuildiqEditButton,
|
|
873
925
|
CnWidgetStyleEditorModal,
|
|
874
926
|
CnLeafMountHost,
|
|
927
|
+
CnSegmentedControl,
|
|
875
928
|
},
|
|
876
929
|
|
|
930
|
+
mixins: [pageViews],
|
|
931
|
+
|
|
877
932
|
inject: {
|
|
878
933
|
/**
|
|
879
934
|
* Buildiq in-app edit state (ADR-041), provided by CnAppRoot as a ref.
|
|
@@ -946,6 +1001,21 @@ export default {
|
|
|
946
1001
|
default: true,
|
|
947
1002
|
},
|
|
948
1003
|
|
|
1004
|
+
/**
|
|
1005
|
+
* Whether a widget draws its overflow Actions menu when neither its
|
|
1006
|
+
* placement nor its definition says (`showActions`). `false` (manifest
|
|
1007
|
+
* `config.showWidgetActions: false`) drops the menu from every such
|
|
1008
|
+
* widget, for a dashboard whose widgets carry a header link and
|
|
1009
|
+
* nothing else. A widget that sets `showActions: true` keeps its menu.
|
|
1010
|
+
* Card widgets have no menu either way.
|
|
1011
|
+
*
|
|
1012
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-dashboard-can-drop-the-widget-actions-menu
|
|
1013
|
+
*/
|
|
1014
|
+
showWidgetActions: {
|
|
1015
|
+
type: Boolean,
|
|
1016
|
+
default: true,
|
|
1017
|
+
},
|
|
1018
|
+
|
|
949
1019
|
/**
|
|
950
1020
|
* Widget definitions array. Each widget defines metadata for rendering.
|
|
951
1021
|
*
|
|
@@ -1861,6 +1931,89 @@ export default {
|
|
|
1861
1931
|
return this.layout.length > 0 || this.widgetRefItems.length > 0
|
|
1862
1932
|
},
|
|
1863
1933
|
|
|
1934
|
+
/**
|
|
1935
|
+
* Whether the grid sections render at all: not while loading, not
|
|
1936
|
+
* while the widget predicates settle, not on the empty page and not
|
|
1937
|
+
* on a widget-ref content page.
|
|
1938
|
+
*
|
|
1939
|
+
* @return {boolean}
|
|
1940
|
+
* @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid
|
|
1941
|
+
*/
|
|
1942
|
+
gridSectionsShown() {
|
|
1943
|
+
if (this.loading || (!this.widgetConditionsSettled && !this.gridEditable)) {
|
|
1944
|
+
return false
|
|
1945
|
+
}
|
|
1946
|
+
if (!this.hasWidgets && !this.hasBodyWidgets && !this.hasViews) {
|
|
1947
|
+
return false
|
|
1948
|
+
}
|
|
1949
|
+
return this.widgetRefItems.length === 0
|
|
1950
|
+
},
|
|
1951
|
+
|
|
1952
|
+
/**
|
|
1953
|
+
* The chosen view's layout as the grid draws it: in live mode the
|
|
1954
|
+
* widgets that would draw nothing leave and the rest close up, as
|
|
1955
|
+
* for the page's own layout.
|
|
1956
|
+
*
|
|
1957
|
+
* @return {Array<object>}
|
|
1958
|
+
* @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so
|
|
1959
|
+
*/
|
|
1960
|
+
viewDisplayLayout() {
|
|
1961
|
+
const items = this.activeView ? this.activeView.layout : []
|
|
1962
|
+
if (this.gridEditable) {
|
|
1963
|
+
return items
|
|
1964
|
+
}
|
|
1965
|
+
const visible = items.filter((item) => !this.isCollapsedWidget(item))
|
|
1966
|
+
return visible.length === items.length ? items : this.compactDisplayLayout(visible)
|
|
1967
|
+
},
|
|
1968
|
+
|
|
1969
|
+
/**
|
|
1970
|
+
* Whether the chosen view has nothing to draw.
|
|
1971
|
+
*
|
|
1972
|
+
* @return {boolean}
|
|
1973
|
+
* @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so
|
|
1974
|
+
*/
|
|
1975
|
+
viewIsEmpty() {
|
|
1976
|
+
return this.hasViews && this.viewDisplayLayout.length === 0
|
|
1977
|
+
},
|
|
1978
|
+
|
|
1979
|
+
/**
|
|
1980
|
+
* The grids this page draws. Without views: the page's own layout,
|
|
1981
|
+
* as it always was. With views: the page's own layout when it has
|
|
1982
|
+
* items, then the chosen view's layout in the region the switch
|
|
1983
|
+
* controls (left out when the view is empty; the empty state takes
|
|
1984
|
+
* the region then).
|
|
1985
|
+
*
|
|
1986
|
+
* @return {Array<{key: string, view: boolean, layout: Array<object>, editable: boolean, attrs: object}>}
|
|
1987
|
+
* @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid
|
|
1988
|
+
*/
|
|
1989
|
+
gridSections() {
|
|
1990
|
+
if (!this.gridSectionsShown) {
|
|
1991
|
+
return []
|
|
1992
|
+
}
|
|
1993
|
+
const page = { key: 'page', view: false, layout: this.displayLayout, editable: this.gridEditable, attrs: {} }
|
|
1994
|
+
if (!this.hasViews) {
|
|
1995
|
+
return [page]
|
|
1996
|
+
}
|
|
1997
|
+
const sections = this.displayLayout.length > 0 ? [page] : []
|
|
1998
|
+
if (!this.viewIsEmpty) {
|
|
1999
|
+
sections.push({
|
|
2000
|
+
key: `view-${this.activeViewId}`,
|
|
2001
|
+
view: true,
|
|
2002
|
+
layout: this.viewDisplayLayout,
|
|
2003
|
+
// A user arrangement covers the page's own layout only.
|
|
2004
|
+
editable: this.gridEditable && !this.userLayout,
|
|
2005
|
+
attrs: {
|
|
2006
|
+
id: this.viewRegionId,
|
|
2007
|
+
role: 'region',
|
|
2008
|
+
'aria-label': this.activeView.label,
|
|
2009
|
+
class: 'cn-page-view-region',
|
|
2010
|
+
'data-testid': 'cn-dashboard-page-view-region',
|
|
2011
|
+
},
|
|
2012
|
+
})
|
|
2013
|
+
}
|
|
2014
|
+
return sections
|
|
2015
|
+
},
|
|
2016
|
+
|
|
1864
2017
|
/**
|
|
1865
2018
|
* The widget settings object handed to CnWidgetStyleEditorModal,
|
|
1866
2019
|
* built from the widget definition currently being configured
|
|
@@ -1991,6 +2144,14 @@ export default {
|
|
|
1991
2144
|
this.evaluateWidgetConditions()
|
|
1992
2145
|
},
|
|
1993
2146
|
},
|
|
2147
|
+
|
|
2148
|
+
/** A view's widgets carry predicates too. */
|
|
2149
|
+
views: {
|
|
2150
|
+
deep: true,
|
|
2151
|
+
handler() {
|
|
2152
|
+
this.evaluateWidgetConditions()
|
|
2153
|
+
},
|
|
2154
|
+
},
|
|
1994
2155
|
},
|
|
1995
2156
|
|
|
1996
2157
|
created() {
|
|
@@ -2855,7 +3016,8 @@ export default {
|
|
|
2855
3016
|
* @spec openspec/changes/live-check-follow-ups/specs/live-check-follow-ups/spec.md#requirement-an-attention-card-says-when-it-could-not-check
|
|
2856
3017
|
*/
|
|
2857
3018
|
async evaluateWidgetConditions() {
|
|
2858
|
-
const
|
|
3019
|
+
const defs = [...(this.widgets || []), ...this.normalizedViews.flatMap((view) => view.widgets)]
|
|
3020
|
+
const conditional = defs.filter((def) => def && def.id && def.type
|
|
2859
3021
|
&& this.widgetDisplayConfig(def).visibleWhen)
|
|
2860
3022
|
// Skip when the CONDITIONAL SET is unchanged: the deep `widgets`
|
|
2861
3023
|
// watch fires on any def edit, but only an added/removed/edited
|
|
@@ -2989,7 +3151,7 @@ export default {
|
|
|
2989
3151
|
*/
|
|
2990
3152
|
getWidgetDef(widgetId) {
|
|
2991
3153
|
const list = Array.isArray(this.widgets) ? this.widgets : []
|
|
2992
|
-
return list.find((w) => w && w.id === widgetId) ||
|
|
3154
|
+
return list.find((w) => w && w.id === widgetId) || this.findViewWidget(widgetId)
|
|
2993
3155
|
},
|
|
2994
3156
|
|
|
2995
3157
|
/**
|
|
@@ -3380,11 +3542,20 @@ export default {
|
|
|
3380
3542
|
* exactly that reason; there is now one rule for every family, so a
|
|
3381
3543
|
* custom slot and a registered widget cannot disagree about it.
|
|
3382
3544
|
*
|
|
3545
|
+
* A greeting header that declares `content.ground: true` sits on the
|
|
3546
|
+
* page ground, so it asks for no card either: one key on the widget
|
|
3547
|
+
* instead of a second one on its placement.
|
|
3548
|
+
*
|
|
3549
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-greeting-can-sit-on-the-page-ground
|
|
3383
3550
|
* @param {object} item the layout placement.
|
|
3384
3551
|
* @return {boolean}
|
|
3385
3552
|
*/
|
|
3386
3553
|
widgetBorderless(item) {
|
|
3387
|
-
|
|
3554
|
+
if (item.borderless === true) {
|
|
3555
|
+
return true
|
|
3556
|
+
}
|
|
3557
|
+
const def = this.getWidgetDef(item.widgetId)
|
|
3558
|
+
return Boolean(def && def.type === 'header' && this.getWidgetContent(item).ground === true)
|
|
3388
3559
|
},
|
|
3389
3560
|
|
|
3390
3561
|
/**
|
|
@@ -3401,7 +3572,7 @@ export default {
|
|
|
3401
3572
|
const def = this.getWidgetDef(item.widgetId)
|
|
3402
3573
|
const value = item.showActions !== undefined ? item.showActions : def?.showActions
|
|
3403
3574
|
if (value === undefined || value === null) {
|
|
3404
|
-
return !this.isCardWidget(item)
|
|
3575
|
+
return this.showWidgetActions && !this.isCardWidget(item)
|
|
3405
3576
|
}
|
|
3406
3577
|
return value !== false
|
|
3407
3578
|
},
|
|
@@ -3994,6 +4165,19 @@ export default {
|
|
|
3994
4165
|
padding: 60px 20px;
|
|
3995
4166
|
}
|
|
3996
4167
|
|
|
4168
|
+
/* The page's view switch on a page without a header row: at the end of its
|
|
4169
|
+
own row, above the grids, where the header would have put it. */
|
|
4170
|
+
.cn-dashboard-page__view-switch {
|
|
4171
|
+
display: flex;
|
|
4172
|
+
justify-content: flex-end;
|
|
4173
|
+
margin-bottom: 12px;
|
|
4174
|
+
}
|
|
4175
|
+
|
|
4176
|
+
/* A view the switch shows with nothing to draw. */
|
|
4177
|
+
.cn-page-view-region--empty {
|
|
4178
|
+
padding: 40px 20px;
|
|
4179
|
+
}
|
|
4180
|
+
|
|
3997
4181
|
.cn-dashboard-page__page-filters {
|
|
3998
4182
|
display: flex;
|
|
3999
4183
|
flex-wrap: wrap;
|
|
@@ -91,9 +91,9 @@
|
|
|
91
91
|
</label>
|
|
92
92
|
</div>
|
|
93
93
|
|
|
94
|
-
<!-- string:
|
|
94
|
+
<!-- string: contains (OpenRegister `[like]`, case-insensitive) -->
|
|
95
95
|
<label v-else class="cn-column-filter__field">
|
|
96
|
-
<span class="cn-column-filter__label">{{
|
|
96
|
+
<span class="cn-column-filter__label">{{ containsLabel }}</span>
|
|
97
97
|
<input
|
|
98
98
|
v-model="draft.value"
|
|
99
99
|
class="cn-column-filter__input"
|
|
@@ -131,7 +131,7 @@ let popoverSeq = 0
|
|
|
131
131
|
*
|
|
132
132
|
* Renders the control that fits the column: a checkbox list for an enum, yes,
|
|
133
133
|
* no or any for a boolean, from and to for a number or a date, a searchable
|
|
134
|
-
* list of referenced objects for a reference, and
|
|
134
|
+
* list of referenced objects for a reference, and a contains box for text.
|
|
135
135
|
* Real inputs throughout, so every control works from the keyboard. Escape
|
|
136
136
|
* closes it and the host returns focus to the filter button.
|
|
137
137
|
*
|
|
@@ -265,8 +265,14 @@ export default {
|
|
|
265
265
|
return t('nextcloud-vue', 'To')
|
|
266
266
|
},
|
|
267
267
|
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
/**
|
|
269
|
+
* Label of the text box: the text filter matches on contains.
|
|
270
|
+
*
|
|
271
|
+
* @return {string}
|
|
272
|
+
* @spec openspec/changes/header-filter-contains/specs/cn-data-table/spec.md#requirement-a-text-header-filter-matches-on-contains
|
|
273
|
+
*/
|
|
274
|
+
containsLabel() {
|
|
275
|
+
return t('nextcloud-vue', 'Contains')
|
|
270
276
|
},
|
|
271
277
|
|
|
272
278
|
clearLabel() {
|
|
@@ -433,4 +433,8 @@ When the schema-driven fetch answers 404 the page shows a not-found state whose
|
|
|
433
433
|
|
|
434
434
|
### Type eyebrow and breadcrumb
|
|
435
435
|
|
|
436
|
-
`showTypeEyebrow` (default `true`) can drop the type label above the record name. `breadcrumb` (`{ label, route?, params?, href? }`) draws a breadcrumb line above the header: that crumb, then the record's name as the current crumb.
|
|
436
|
+
`showTypeEyebrow` (default `true`) can drop the type label above the record name. `breadcrumb` (`{ label, route?, params?, href?, icon? }`) draws a breadcrumb line above the header: that crumb, then the record's name as the current crumb. The label shows as text; `icon` draws an icon instead.
|
|
437
|
+
|
|
438
|
+
### Header card and header widget
|
|
439
|
+
|
|
440
|
+
`headerCard` (default `false`) draws the header as a bordered card. `headerWidget` (default `''`) names a widget in `widgets` to render inside the header under the title, without a card of its own and out of the body grid: the stages bars of the board's case card.
|