@conduction/nextcloud-vue 2.69.0 → 2.71.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/CnActionsBar/CnActionsBar.vue2.js +25 -0
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +155 -152
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +77 -0
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +8 -8
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +151 -13
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +3 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue.js +1 -0
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +28 -0
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +4 -2
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js +25 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js +32 -17
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue2.js +14 -1
- package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue2.js.map +1 -1
- package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +43 -2
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +3 -3
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +25 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +40 -43
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +35 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +54 -3
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +6 -3
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +28 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +3 -2
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue2.js +12 -0
- package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +9 -0
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +29 -2
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +71 -34
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +54 -7
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +26 -8
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +165 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +69 -26
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +4 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +46 -32
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +17 -3
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +25 -24
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.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 +27 -0
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +7 -0
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +24 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +11 -0
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +4 -2
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +30 -9
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +15 -2
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js +31 -32
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
- package/dist/esm/composables/useWalkthrough.js +11 -3
- package/dist/esm/composables/useWalkthrough.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +198 -0
- package/dist/esm/utils/capabilityComparison.js +29 -1
- package/dist/esm/utils/capabilityComparison.js.map +1 -1
- package/dist/esm/utils/columnFilters.js +54 -4
- package/dist/esm/utils/columnFilters.js.map +1 -1
- package/dist/esm/utils/userAutocomplete.js +69 -3
- package/dist/esm/utils/userAutocomplete.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 +2778 -1630
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +198 -0
- package/package.json +1 -1
- package/src/components/CnActionsBar/CnActionsBar.md +2 -0
- package/src/components/CnActionsBar/CnActionsBar.vue +28 -2
- package/src/components/CnAppNav/CnAppNav.vue +85 -8
- package/src/components/CnAppRoot/CnAppRoot.vue +153 -13
- package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +45 -0
- package/src/components/CnCalendarWidget/CnCalendarWidget.vue +32 -4
- package/src/components/CnCapabilityTable/CnCapabilityTable.vue +14 -0
- package/src/components/CnDashboardGrid/CnDashboardGrid.md +2 -0
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +54 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +46 -19
- package/src/components/CnDataTable/CnDataTable.vue +35 -1
- package/src/components/CnDetailPage/CnDetailPage.md +2 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +57 -3
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +30 -1
- package/src/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue +12 -0
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +9 -0
- package/src/components/CnFormDialog/CnFormDialog.vue +62 -2
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +95 -8
- package/src/components/CnIndexPage/CnIndexPage.vue +194 -7
- package/src/components/CnNextStepCard/CnNextStepCard.vue +11 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +4 -1
- package/src/components/CnObjectSidebar/CnNotesTab.vue +1 -1
- package/src/components/CnSetupWizard/CnSetupWizard.vue +7 -0
- package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +34 -7
- package/src/components/CnStagesWidget/CnStagesWidget.vue +19 -0
- package/src/components/CnStatWidget/CnStatWidget.vue +36 -0
- package/src/components/CnStatsBlock/CnStatsBlock.md +2 -0
- package/src/components/CnStatsBlock/CnStatsBlock.vue +25 -2
- package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +13 -0
- package/src/components/CnWalkthrough/CnWalkthrough.vue +30 -9
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +24 -3
- package/src/composables/useWalkthrough.js +11 -3
- package/src/css/dashboard.css +44 -0
- package/src/css/detail-page.css +10 -0
- package/src/css/index-page.css +12 -0
- package/src/css/kpi-card.css +15 -0
- package/src/schemas/app-manifest-v2.schema.json +47 -5
- package/src/utils/capabilityComparison.js +28 -0
- package/src/utils/columnFilters.js +54 -4
- package/src/utils/userAutocomplete.js +68 -2
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -19,8 +19,28 @@
|
|
|
19
19
|
<CnPageHeader
|
|
20
20
|
:title="title"
|
|
21
21
|
:description="headerDescription"
|
|
22
|
-
:icon="resolvedIcon"
|
|
23
|
-
:visuallyHidden="!showTitle"
|
|
22
|
+
:icon="showTitleIcon ? resolvedIcon : ''"
|
|
23
|
+
:visuallyHidden="!showTitle">
|
|
24
|
+
<!-- The board's header buttons (`headerButtons`), beside the
|
|
25
|
+
title. Declaring them takes the Views and Actions menus
|
|
26
|
+
(and the Add / Export controls a button takes over) out of
|
|
27
|
+
the actions bar. -->
|
|
28
|
+
<template v-if="headerButtonsShown" #extra>
|
|
29
|
+
<div class="cn-index-page__header-buttons" data-testid="cn-index-header-buttons">
|
|
30
|
+
<NcButton
|
|
31
|
+
v-for="button in resolvedHeaderButtons"
|
|
32
|
+
:key="button.key"
|
|
33
|
+
:variant="button.variant"
|
|
34
|
+
:data-testid="`cn-index-header-button-${button.key}`"
|
|
35
|
+
@click="onHeaderButton(button)">
|
|
36
|
+
<template v-if="button.icon" #icon>
|
|
37
|
+
<CnIcon :name="button.icon" :size="20" />
|
|
38
|
+
</template>
|
|
39
|
+
{{ button.label }}
|
|
40
|
+
</NcButton>
|
|
41
|
+
</div>
|
|
42
|
+
</template>
|
|
43
|
+
</CnPageHeader>
|
|
24
44
|
</slot>
|
|
25
45
|
|
|
26
46
|
<!-- Optional content below header, above actions bar -->
|
|
@@ -64,7 +84,9 @@
|
|
|
64
84
|
:refreshDisabled="refreshDisabled"
|
|
65
85
|
:addDisabled="addDisabled"
|
|
66
86
|
:addTo="addLinkTo"
|
|
67
|
-
:showAdd="effectiveShowAdd"
|
|
87
|
+
:showAdd="effectiveShowAdd && !headerButtonTakes('add')"
|
|
88
|
+
:showCount="showCount"
|
|
89
|
+
:showActionsMenu="!headerButtonsShown"
|
|
68
90
|
:showSidebarToggle="hasSidebar"
|
|
69
91
|
:sidebarOpen="sidebarOpen"
|
|
70
92
|
:headerActions="mergedHeaderActions"
|
|
@@ -111,12 +133,12 @@
|
|
|
111
133
|
views, export, page config — grouped together and kept apart from
|
|
112
134
|
the app-specific buttons in `#actions`, with Add sitting between
|
|
113
135
|
the two groups rather than before both (dossiq Cases/Queue). -->
|
|
114
|
-
<template v-if="isEditMode ||
|
|
136
|
+
<template v-if="isEditMode || barShowsExportMenu || barShowsSavedViews" #actions-end>
|
|
115
137
|
<!-- Saved views (opt-in via `allowSavedViews`): lists the user's
|
|
116
138
|
OpenRegister saved-search views; applying one writes its stored
|
|
117
139
|
filters/search/sort into the route query. -->
|
|
118
140
|
<CnSavedViewsControl
|
|
119
|
-
v-if="
|
|
141
|
+
v-if="barShowsSavedViews"
|
|
120
142
|
:views="viewsForControl"
|
|
121
143
|
:loading="savedViewsLoading"
|
|
122
144
|
:currentUserId="currentSavedViewsUserId"
|
|
@@ -128,7 +150,7 @@
|
|
|
128
150
|
CSV/Excel entries navigate to OR's export-leaf URL, passing the
|
|
129
151
|
current route's query params through as filters. -->
|
|
130
152
|
<NcActions
|
|
131
|
-
v-if="
|
|
153
|
+
v-if="barShowsExportMenu"
|
|
132
154
|
:forceName="true"
|
|
133
155
|
:menuName="t('nextcloud-vue', 'Export')"
|
|
134
156
|
data-testid="cn-index-export-menu"
|
|
@@ -466,7 +488,7 @@
|
|
|
466
488
|
:includeColumns="includeColumns"
|
|
467
489
|
:columnOverrides="columnOverrides"
|
|
468
490
|
:rowClass="rowClass"
|
|
469
|
-
:filterable="
|
|
491
|
+
:filterable="tableHeaderFilters"
|
|
470
492
|
:activeFilters="effectiveActiveFilters"
|
|
471
493
|
:filterRegister="typeof register === 'string' ? register : ''"
|
|
472
494
|
@columnFilter="onColumnFilterEvent"
|
|
@@ -1225,6 +1247,51 @@ export default {
|
|
|
1225
1247
|
default: false,
|
|
1226
1248
|
},
|
|
1227
1249
|
|
|
1250
|
+
/**
|
|
1251
|
+
* Whether the page header draws its icon before the title. `false`
|
|
1252
|
+
* (manifest `config.showTitleIcon: false`) drops it, for a title that
|
|
1253
|
+
* stands alone as the board draws it. True by default.
|
|
1254
|
+
*
|
|
1255
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
1256
|
+
*/
|
|
1257
|
+
showTitleIcon: {
|
|
1258
|
+
type: Boolean,
|
|
1259
|
+
default: true,
|
|
1260
|
+
},
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Whether the actions bar shows its "Showing 20 of 258" line.
|
|
1264
|
+
* `false` (manifest `config.showCount: false`) drops it, for a page
|
|
1265
|
+
* whose title line already gives the total (`countSubtitle`). True by
|
|
1266
|
+
* default.
|
|
1267
|
+
*
|
|
1268
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
1269
|
+
*/
|
|
1270
|
+
showCount: {
|
|
1271
|
+
type: Boolean,
|
|
1272
|
+
default: true,
|
|
1273
|
+
},
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* Buttons beside the page title, as the board's "Export" and "New
|
|
1277
|
+
* case" (manifest `config.headerButtons`). Each is `{ label?, action,
|
|
1278
|
+
* variant?, icon?, format?, id? }`: `action` is `add` (the Add flow;
|
|
1279
|
+
* its label defaults to the Add label), `export` (the export leaf in
|
|
1280
|
+
* `format`, `csv` by default, else the export dialog), `import`,
|
|
1281
|
+
* `refresh`, or the id of a `headerActions` entry; `variant` is
|
|
1282
|
+
* `primary` or `secondary` (the default). Shown only with
|
|
1283
|
+
* `showTitle`. When they show, the actions bar drops its Views and
|
|
1284
|
+
* Actions menus, and the Add button and Export menu when a button
|
|
1285
|
+
* takes their action. Empty (the default) changes nothing.
|
|
1286
|
+
*
|
|
1287
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
1288
|
+
* @type {Array<{label?: string, action: string, variant?: ('primary'|'secondary'), icon?: string, format?: ('csv'|'excel'), id?: string}>}
|
|
1289
|
+
*/
|
|
1290
|
+
headerButtons: {
|
|
1291
|
+
type: Array,
|
|
1292
|
+
default: () => [],
|
|
1293
|
+
},
|
|
1294
|
+
|
|
1228
1295
|
/** Optional MDI icon name. Defaults to schema.icon when a schema is provided. */
|
|
1229
1296
|
icon: {
|
|
1230
1297
|
type: String,
|
|
@@ -3806,6 +3873,28 @@ export default {
|
|
|
3806
3873
|
},
|
|
3807
3874
|
|
|
3808
3875
|
/** Resolved schema OBJECT (for column generation / icons / labels). */
|
|
3876
|
+
/**
|
|
3877
|
+
* Whether the table shows its header filters. A self-fetching page
|
|
3878
|
+
* applies them itself, with or without a resolved schema (the columns
|
|
3879
|
+
* then say how each one filters, else a text filter on contains). A
|
|
3880
|
+
* host-fed table shows them when a schema came along, as before, or
|
|
3881
|
+
* when the host listens for `filter-change`; a filter nobody applies
|
|
3882
|
+
* would be a control that does nothing.
|
|
3883
|
+
*
|
|
3884
|
+
* @spec openspec/changes/audit-round-lib-fixes/specs/cn-data-table/spec.md
|
|
3885
|
+
* @return {boolean} True when header filters show.
|
|
3886
|
+
*/
|
|
3887
|
+
tableHeaderFilters() {
|
|
3888
|
+
if (!this.headerFilters) {
|
|
3889
|
+
return false
|
|
3890
|
+
}
|
|
3891
|
+
if (this.effectiveSchema || this.isSelfFetchMode) {
|
|
3892
|
+
return true
|
|
3893
|
+
}
|
|
3894
|
+
const vnodeProps = (this.$ && this.$.vnode && this.$.vnode.props) || {}
|
|
3895
|
+
return typeof vnodeProps.onFilterChange === 'function' || Array.isArray(vnodeProps.onFilterChange)
|
|
3896
|
+
},
|
|
3897
|
+
|
|
3809
3898
|
effectiveSchema() {
|
|
3810
3899
|
if (this.isSelfFetchMode) {
|
|
3811
3900
|
return this.list.schema.value
|
|
@@ -4284,6 +4373,67 @@ export default {
|
|
|
4284
4373
|
return resolveDeepTokens(seed, {})
|
|
4285
4374
|
},
|
|
4286
4375
|
|
|
4376
|
+
/**
|
|
4377
|
+
* The declared header buttons with a label, translated, each with a
|
|
4378
|
+
* stable key and a variant.
|
|
4379
|
+
*
|
|
4380
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
4381
|
+
* @return {Array<{key: string, label: string, action: string, variant: string, icon: string, format: string}>}
|
|
4382
|
+
*/
|
|
4383
|
+
resolvedHeaderButtons() {
|
|
4384
|
+
const declared = Array.isArray(this.headerButtons) ? this.headerButtons : []
|
|
4385
|
+
return declared
|
|
4386
|
+
.filter((button) => button && typeof button === 'object' && typeof button.action === 'string' && button.action !== '')
|
|
4387
|
+
.map((button, index) => {
|
|
4388
|
+
let label = typeof button.label === 'string' && button.label !== '' ? this.cnTranslate(button.label) : ''
|
|
4389
|
+
if (label === '' && button.action === 'add') {
|
|
4390
|
+
label = this.resolvedAddLabel
|
|
4391
|
+
}
|
|
4392
|
+
return {
|
|
4393
|
+
key: String(button.id || button.action || index),
|
|
4394
|
+
label,
|
|
4395
|
+
action: button.action,
|
|
4396
|
+
variant: button.variant === 'primary' ? 'primary' : 'secondary',
|
|
4397
|
+
icon: typeof button.icon === 'string' ? button.icon : '',
|
|
4398
|
+
format: button.format === 'excel' ? 'excel' : 'csv',
|
|
4399
|
+
}
|
|
4400
|
+
})
|
|
4401
|
+
.filter((button) => button.label !== '')
|
|
4402
|
+
},
|
|
4403
|
+
|
|
4404
|
+
/**
|
|
4405
|
+
* Whether the header buttons render: there are some, the title shows
|
|
4406
|
+
* (they sit beside it) and no `#header` slot replaces the header.
|
|
4407
|
+
*
|
|
4408
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
4409
|
+
* @return {boolean}
|
|
4410
|
+
*/
|
|
4411
|
+
headerButtonsShown() {
|
|
4412
|
+
return this.showTitle && !this.$slots.header && this.resolvedHeaderButtons.length > 0
|
|
4413
|
+
},
|
|
4414
|
+
|
|
4415
|
+
/**
|
|
4416
|
+
* Whether the actions bar shows the saved-views control: opted in
|
|
4417
|
+
* with `allowSavedViews` and not given up for header buttons.
|
|
4418
|
+
*
|
|
4419
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
4420
|
+
* @return {boolean}
|
|
4421
|
+
*/
|
|
4422
|
+
barShowsSavedViews() {
|
|
4423
|
+
return Boolean(this.allowSavedViews) && !this.headerButtonsShown
|
|
4424
|
+
},
|
|
4425
|
+
|
|
4426
|
+
/**
|
|
4427
|
+
* Whether the actions bar shows the Export menu: `showExportMenu`,
|
|
4428
|
+
* unless a header button took the export over.
|
|
4429
|
+
*
|
|
4430
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
4431
|
+
* @return {boolean}
|
|
4432
|
+
*/
|
|
4433
|
+
barShowsExportMenu() {
|
|
4434
|
+
return this.showExportMenu && !this.headerButtonTakes('export')
|
|
4435
|
+
},
|
|
4436
|
+
|
|
4287
4437
|
/**
|
|
4288
4438
|
* The header's description line: `countSubtitle` with the total
|
|
4289
4439
|
* filled in when one is known, else `description`.
|
|
@@ -5086,6 +5236,43 @@ export default {
|
|
|
5086
5236
|
this.$emit('open-modal', { target, props: { selectedIds, count, ...own } })
|
|
5087
5237
|
},
|
|
5088
5238
|
|
|
5239
|
+
/**
|
|
5240
|
+
* Whether a shown header button takes `action` over from the bar.
|
|
5241
|
+
*
|
|
5242
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
5243
|
+
* @param {string} action The action, e.g. `add`.
|
|
5244
|
+
* @return {boolean}
|
|
5245
|
+
*/
|
|
5246
|
+
headerButtonTakes(action) {
|
|
5247
|
+
return this.headerButtonsShown && this.resolvedHeaderButtons.some((button) => button.action === action)
|
|
5248
|
+
},
|
|
5249
|
+
|
|
5250
|
+
/**
|
|
5251
|
+
* A header button was clicked: run its built-in action, or dispatch
|
|
5252
|
+
* it as the `headerActions` entry with that id.
|
|
5253
|
+
*
|
|
5254
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-an-index-page-can-take-the-board-header
|
|
5255
|
+
* @param {{action: string, format: string}} button The resolved button.
|
|
5256
|
+
* @return {void}
|
|
5257
|
+
*/
|
|
5258
|
+
onHeaderButton(button) {
|
|
5259
|
+
if (button.action === 'add') {
|
|
5260
|
+
this.onAddClick()
|
|
5261
|
+
} else if (button.action === 'export') {
|
|
5262
|
+
if (this.register && this.exportSchemaSlug) {
|
|
5263
|
+
this.onExportClick(button.format)
|
|
5264
|
+
} else {
|
|
5265
|
+
this.showExportDialog = true
|
|
5266
|
+
}
|
|
5267
|
+
} else if (button.action === 'import') {
|
|
5268
|
+
this.showImportDialog = true
|
|
5269
|
+
} else if (button.action === 'refresh') {
|
|
5270
|
+
this.onRefreshEvent()
|
|
5271
|
+
} else {
|
|
5272
|
+
this.onHeaderAction({ action: button.action, id: button.action })
|
|
5273
|
+
}
|
|
5274
|
+
},
|
|
5275
|
+
|
|
5089
5276
|
/**
|
|
5090
5277
|
* Click dispatch from CnActionsBar's `@header-action`. Looks
|
|
5091
5278
|
* up the resolved entry by id, invokes its handler if any,
|
|
@@ -241,6 +241,17 @@ export default {
|
|
|
241
241
|
text-transform: uppercase;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
+
/* The title is a small kicker, not a section heading, but it is an <h3> (or
|
|
245
|
+
whatever `titleTag` says) for the outline, and a theme that sizes every
|
|
246
|
+
heading with !important (thematiq's nldesign sheet: `h3 { font-size:
|
|
247
|
+
var(--nldesign-component-heading-3-font-size) !important }`) blew it up to
|
|
248
|
+
an 18px uppercase heading. Only !important beats !important; the doubled
|
|
249
|
+
class makes this the more specific rule. Without such a theme the size is
|
|
250
|
+
the 0.85em above, unchanged. */
|
|
251
|
+
.cn-next-step-card__title.cn-next-step-card__title {
|
|
252
|
+
font-size: 0.85em !important;
|
|
253
|
+
}
|
|
254
|
+
|
|
244
255
|
.cn-next-step-card__list {
|
|
245
256
|
display: grid;
|
|
246
257
|
gap: calc(2 * var(--default-grid-baseline));
|
|
@@ -614,7 +614,10 @@ export default {
|
|
|
614
614
|
return { key: c, label: headingFor(c) }
|
|
615
615
|
}
|
|
616
616
|
const out = { key: c.key, label: c.label || headingFor(c.key) }
|
|
617
|
-
|
|
617
|
+
// `secondary` (a second, muted line under the cell) rides
|
|
618
|
+
// along too: the table draws it, and dropping it here took the
|
|
619
|
+
// list rows' second line away (zuiddrecht-pixel-gaps-3).
|
|
620
|
+
for (const k of ['format', 'widget', 'widgetProps', 'formatter', 'align', 'width', 'type', 'enum', 'enumLabels', 'sortable', 'secondary']) {
|
|
618
621
|
if (c[k] !== undefined) {
|
|
619
622
|
out[k] = c[k]
|
|
620
623
|
}
|
|
@@ -279,7 +279,7 @@ export default {
|
|
|
279
279
|
* @param {(suggestions: Array<object>) => void} callback Receives the suggestion array.
|
|
280
280
|
*/
|
|
281
281
|
async fetchMentionSuggestions(search, callback) {
|
|
282
|
-
const users = await searchNextcloudUsers(search)
|
|
282
|
+
const users = await searchNextcloudUsers(search, { includeCurrentUser: false })
|
|
283
283
|
callback(users.map((user) => ({
|
|
284
284
|
id: user.id,
|
|
285
285
|
label: user.label,
|
|
@@ -123,6 +123,13 @@
|
|
|
123
123
|
|
|
124
124
|
<!-- config-fields -->
|
|
125
125
|
<template v-else-if="step.type === 'config-fields'">
|
|
126
|
+
<!-- The step's intro, drawn like choice and run-action steps.
|
|
127
|
+
It was left out here, so pipelinq's organisation step
|
|
128
|
+
("Your organisation details…") showed fields with no
|
|
129
|
+
word about what they were for. -->
|
|
130
|
+
<NcNoteCard v-if="step.body" type="info" data-testid="cn-setup-step-intro">
|
|
131
|
+
{{ stepBody(step) }}
|
|
132
|
+
</NcNoteCard>
|
|
126
133
|
<div
|
|
127
134
|
v-for="field in fieldsFor(step)"
|
|
128
135
|
:key="field.key"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
SPDX-License-Identifier: EUPL-1.2
|
|
4
4
|
-->
|
|
5
5
|
<template>
|
|
6
|
-
<div class="cn-stacked-bar" data-testid="cn-stacked-bar">
|
|
6
|
+
<div class="cn-stacked-bar" :class="{ 'cn-stacked-bar--inset': inset }" data-testid="cn-stacked-bar">
|
|
7
7
|
<div v-if="loading" class="cn-stacked-bar__state" role="status">
|
|
8
8
|
<NcLoadingIcon :size="20" />
|
|
9
9
|
<span>{{ loadingLabel }}</span>
|
|
@@ -11,9 +11,14 @@
|
|
|
11
11
|
<p v-else-if="error" class="cn-stacked-bar__state" role="status">
|
|
12
12
|
{{ errorLabel }}
|
|
13
13
|
</p>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
<!-- The designed empty state the list widgets use, compact: a bare
|
|
15
|
+
line of text read as a broken widget in an empty card. -->
|
|
16
|
+
<CnWidgetEmptyState
|
|
17
|
+
v-else-if="total === 0"
|
|
18
|
+
:name="emptyLabel"
|
|
19
|
+
compact
|
|
20
|
+
class="cn-stacked-bar__empty"
|
|
21
|
+
data-testid="cn-stacked-bar-empty" />
|
|
17
22
|
<template v-else>
|
|
18
23
|
<!-- The bar is a picture of the legend below it. The legend holds
|
|
19
24
|
every label and number, so the bar itself is hidden from
|
|
@@ -50,6 +55,7 @@
|
|
|
50
55
|
<script>
|
|
51
56
|
import { translate as t } from '@nextcloud/l10n'
|
|
52
57
|
import { NcLoadingIcon } from '@nextcloud/vue'
|
|
58
|
+
import CnWidgetEmptyState from '../CnWidgetEmptyState/CnWidgetEmptyState.vue'
|
|
53
59
|
import { fetchGroupedCounts } from '../../utils/fetchAggregate.js'
|
|
54
60
|
|
|
55
61
|
/** The lightest step keeps this share of the primary colour, so it still stands out from the page. */
|
|
@@ -114,7 +120,7 @@ export function rampColor(index, count) {
|
|
|
114
120
|
export default {
|
|
115
121
|
name: 'CnStackedBarWidget',
|
|
116
122
|
|
|
117
|
-
components: { NcLoadingIcon },
|
|
123
|
+
components: { CnWidgetEmptyState, NcLoadingIcon },
|
|
118
124
|
|
|
119
125
|
inject: {
|
|
120
126
|
/**
|
|
@@ -133,9 +139,11 @@ export default {
|
|
|
133
139
|
* group keys in the order they render; groups it does not list follow
|
|
134
140
|
* in the order they arrive, and a listed key without records renders
|
|
135
141
|
* with a count of 0. `labels` maps a group key to its label.
|
|
136
|
-
* `emptyText` is shown when there is nothing to count.
|
|
142
|
+
* `emptyText` is shown when there is nothing to count. `inset: true`
|
|
143
|
+
* draws the bar and legend inside the board's inset (16px above, 24px
|
|
144
|
+
* at the sides, 22px below) instead of from card edge to card edge.
|
|
137
145
|
*
|
|
138
|
-
* @type {{source?: {register?: string, schema?: string, groupBy?: string, filter?: object}, segments?: Array<{key?: string, label: string, value: number}>, order?: Array<string>, labels?: {[key: string]: string}, emptyText?: string}}
|
|
146
|
+
* @type {{inset?: boolean, source?: {register?: string, schema?: string, groupBy?: string, filter?: object}, segments?: Array<{key?: string, label: string, value: number}>, order?: Array<string>, labels?: {[key: string]: string}, emptyText?: string}}
|
|
139
147
|
*/
|
|
140
148
|
content: {
|
|
141
149
|
type: Object,
|
|
@@ -163,6 +171,17 @@ export default {
|
|
|
163
171
|
},
|
|
164
172
|
|
|
165
173
|
computed: {
|
|
174
|
+
/**
|
|
175
|
+
* Whether the widget draws the board's inset (`content.inset`). Off
|
|
176
|
+
* by default, which keeps it edge to edge as before.
|
|
177
|
+
*
|
|
178
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-strip-and-a-stacked-bar-can-take-the-board-inset
|
|
179
|
+
* @return {boolean}
|
|
180
|
+
*/
|
|
181
|
+
inset() {
|
|
182
|
+
return Boolean(this.content && this.content.inset === true)
|
|
183
|
+
},
|
|
184
|
+
|
|
166
185
|
/**
|
|
167
186
|
* The translate function in use.
|
|
168
187
|
*
|
|
@@ -353,6 +372,14 @@ export default {
|
|
|
353
372
|
width: 100%;
|
|
354
373
|
}
|
|
355
374
|
|
|
375
|
+
/* `content.inset: true`: the board's inset inside the card (zuiddrecht-pixel-
|
|
376
|
+
gaps-3). A dashboard renders its widgets flush, so without it the strip ran
|
|
377
|
+
from card edge to card edge. Theme hook: --cn-widget-board-inset. */
|
|
378
|
+
.cn-stacked-bar--inset {
|
|
379
|
+
box-sizing: border-box;
|
|
380
|
+
padding: var(--cn-widget-board-inset, 16px 24px 22px);
|
|
381
|
+
}
|
|
382
|
+
|
|
356
383
|
.cn-stacked-bar__state {
|
|
357
384
|
display: flex;
|
|
358
385
|
align-items: center;
|
|
@@ -1502,6 +1502,25 @@ button.cn-stages-widget__bar-label {
|
|
|
1502
1502
|
cursor: pointer;
|
|
1503
1503
|
}
|
|
1504
1504
|
|
|
1505
|
+
/* The same label under a theme that restyles every button with !important
|
|
1506
|
+
(thematiq's nldesign sheet: `button:not(.action-button)` gets 8px 16px
|
|
1507
|
+
padding, `min-width: max-content` and `overflow: visible`), and under core's
|
|
1508
|
+
`margin: 3px 3px 3px 0`, which outranks the scoped base rule. Together they
|
|
1509
|
+
put each clickable label about 10px below the current step's <span> and let
|
|
1510
|
+
a long label run over its neighbours, so eight Woo steps overlapped instead
|
|
1511
|
+
of ending in an ellipsis. Only !important beats !important; this selector is
|
|
1512
|
+
the more specific of the two. Without such a theme nothing changes: these
|
|
1513
|
+
are the values the base rule already sets. */
|
|
1514
|
+
button.cn-stages-widget__bar-label.cn-stages-widget__bar-label {
|
|
1515
|
+
min-width: 0 !important;
|
|
1516
|
+
margin: 0 !important;
|
|
1517
|
+
padding: 0 !important;
|
|
1518
|
+
border-width: 0 !important;
|
|
1519
|
+
overflow: hidden !important;
|
|
1520
|
+
text-overflow: ellipsis !important;
|
|
1521
|
+
white-space: nowrap !important;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1505
1524
|
button.cn-stages-widget__bar-label[aria-disabled="true"] {
|
|
1506
1525
|
cursor: not-allowed;
|
|
1507
1526
|
}
|
|
@@ -111,6 +111,15 @@
|
|
|
111
111
|
data-testid="cn-stat-widget-caption">
|
|
112
112
|
{{ resolvedCaption }}
|
|
113
113
|
</span>
|
|
114
|
+
<!-- A second caption line (`content.note`), as LpStart's "3
|
|
115
|
+
deadlines this week" under the count. Static text for now. -->
|
|
116
|
+
<span
|
|
117
|
+
v-if="!displayLoading && !displayError && resolvedNote"
|
|
118
|
+
class="cn-kpi-card__label cn-stat-widget__note cn-kpi-card__caption-line"
|
|
119
|
+
:class="noteVariantClass"
|
|
120
|
+
data-testid="cn-stat-widget-note">
|
|
121
|
+
{{ resolvedNote }}
|
|
122
|
+
</span>
|
|
114
123
|
</div>
|
|
115
124
|
</component>
|
|
116
125
|
</template>
|
|
@@ -663,6 +672,33 @@ export default {
|
|
|
663
672
|
return rules.find((r) => r && this.matchesRule(current, r)) || null
|
|
664
673
|
},
|
|
665
674
|
|
|
675
|
+
/**
|
|
676
|
+
* The second caption line: `content.note` through the host translate
|
|
677
|
+
* function, or '' without it.
|
|
678
|
+
*
|
|
679
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-stat-tile-can-carry-a-second-caption-line
|
|
680
|
+
* @return {string}
|
|
681
|
+
*/
|
|
682
|
+
resolvedNote() {
|
|
683
|
+
const note = this.content && this.content.note
|
|
684
|
+
return typeof note === 'string' && note !== '' ? this.effectiveTranslate(note) : ''
|
|
685
|
+
},
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* The colour class of the second caption line (`content.noteVariant`,
|
|
689
|
+
* the same names as `captionVariant`), or '' for the muted default.
|
|
690
|
+
*
|
|
691
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-stat-tile-can-carry-a-second-caption-line
|
|
692
|
+
* @return {string}
|
|
693
|
+
*/
|
|
694
|
+
noteVariantClass() {
|
|
695
|
+
const variant = this.content && this.content.noteVariant
|
|
696
|
+
if (!variant || variant === 'default' || !Object.hasOwn(VARIANT_COLORS, variant)) {
|
|
697
|
+
return ''
|
|
698
|
+
}
|
|
699
|
+
return `cn-kpi-card__label--${variant === 'danger' ? 'error' : variant}`
|
|
700
|
+
},
|
|
701
|
+
|
|
666
702
|
/**
|
|
667
703
|
* The caption's colour class: the matching override's
|
|
668
704
|
* `captionVariant`, else `content.captionVariant`, as
|
|
@@ -151,3 +151,5 @@ export default {
|
|
|
151
151
|
| Slot | Scope | Description |
|
|
152
152
|
|---|---|---|
|
|
153
153
|
| `value` | `{ count, formatted }` | Override the prominently-displayed value — render a pre-formatted string (currency, percent, a "—" placeholder, …). `count` is the raw `count` prop; `formatted` is the locale-formatted string the default slot renders. Useful for currency / unit prefixes (e.g. `€{{ formatted }}`). |
|
|
154
|
+
|
|
155
|
+
`layout` (String, default empty): `stacked` is the board's tile, as CnStatWidget `content.layout: "stacked"`: no icon circle, a 14px muted title, the number at 34px/700 and the unit on a muted line under it.
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
v-bind="componentAttrs"
|
|
20
20
|
@click="onClick">
|
|
21
21
|
<!-- Icon -->
|
|
22
|
-
<div v-if="hasIcon" class="cn-kpi-card__icon cn-stats-block__icon" :class="iconClasses">
|
|
22
|
+
<div v-if="hasIcon && !isStacked" class="cn-kpi-card__icon cn-stats-block__icon" :class="iconClasses">
|
|
23
23
|
<slot name="icon">
|
|
24
24
|
<component :is="icon" v-if="icon" :size="iconSize" />
|
|
25
25
|
</slot>
|
|
@@ -249,6 +249,18 @@ export default {
|
|
|
249
249
|
default: false,
|
|
250
250
|
},
|
|
251
251
|
|
|
252
|
+
/**
|
|
253
|
+
* `stacked` is the board's tile, as CnStatWidget `content.layout:
|
|
254
|
+
* "stacked"`: no icon circle, a 14px muted title, the number at
|
|
255
|
+
* 34px/700 in the text colour. Empty (the default) keeps the KPI card.
|
|
256
|
+
*
|
|
257
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-stats-block-can-take-the-stacked-board-look
|
|
258
|
+
*/
|
|
259
|
+
layout: {
|
|
260
|
+
type: String,
|
|
261
|
+
default: '',
|
|
262
|
+
},
|
|
263
|
+
|
|
252
264
|
/**
|
|
253
265
|
* Lay the icon left of the content. No longer needed — this is the
|
|
254
266
|
* canonical card's own layout — and kept so existing callers that pass
|
|
@@ -366,13 +378,24 @@ export default {
|
|
|
366
378
|
return {}
|
|
367
379
|
},
|
|
368
380
|
|
|
381
|
+
/**
|
|
382
|
+
* Whether the block takes the stacked board look (`layout`).
|
|
383
|
+
*
|
|
384
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-stats-block-can-take-the-stacked-board-look
|
|
385
|
+
* @return {boolean}
|
|
386
|
+
*/
|
|
387
|
+
isStacked() {
|
|
388
|
+
return this.layout === 'stacked'
|
|
389
|
+
},
|
|
390
|
+
|
|
369
391
|
rootClasses() {
|
|
370
392
|
return {
|
|
371
393
|
// Canonical + legacy, in pairs: the canonical class carries the
|
|
372
394
|
// look, the legacy one keeps existing app CSS matching.
|
|
373
395
|
// The canonical card is already horizontal, so the legacy pair
|
|
374
396
|
// is emitted for app CSS but carries no look of its own.
|
|
375
|
-
'cn-kpi-card--horizontal': this.horizontal || !this.vertical,
|
|
397
|
+
'cn-kpi-card--horizontal': !this.isStacked && (this.horizontal || !this.vertical),
|
|
398
|
+
'cn-kpi-card--stacked': this.isStacked,
|
|
376
399
|
'cn-stats-block--horizontal': this.horizontal || !this.vertical,
|
|
377
400
|
'cn-kpi-card--vertical': this.vertical,
|
|
378
401
|
'cn-stats-block--vertical': this.vertical,
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
:showZeroCount="showZeroCount"
|
|
33
33
|
:horizontal="horizontal"
|
|
34
34
|
:vertical="vertical"
|
|
35
|
+
:layout="layout"
|
|
35
36
|
:filled="filled"
|
|
36
37
|
:clickable="!!view.route"
|
|
37
38
|
:route="view.route || null">
|
|
@@ -54,6 +55,7 @@
|
|
|
54
55
|
:showZeroCount="showZeroCount"
|
|
55
56
|
:horizontal="horizontal"
|
|
56
57
|
:vertical="vertical"
|
|
58
|
+
:layout="layout"
|
|
57
59
|
:filled="filled"
|
|
58
60
|
:clickable="!!route"
|
|
59
61
|
:route="route">
|
|
@@ -260,6 +262,17 @@ export default {
|
|
|
260
262
|
default: false,
|
|
261
263
|
},
|
|
262
264
|
|
|
265
|
+
/**
|
|
266
|
+
* `stacked` gives every block the board look (see CnStatsBlock
|
|
267
|
+
* `layout`). Empty (the default) keeps the KPI card.
|
|
268
|
+
*
|
|
269
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-stats-block-can-take-the-stacked-board-look
|
|
270
|
+
*/
|
|
271
|
+
layout: {
|
|
272
|
+
type: String,
|
|
273
|
+
default: '',
|
|
274
|
+
},
|
|
275
|
+
|
|
263
276
|
/**
|
|
264
277
|
* Draw each tile's own grey box. Off by default — the widget is
|
|
265
278
|
* rendered inside a CnWidgetWrapper that already draws a card.
|
|
@@ -172,6 +172,12 @@ export default {
|
|
|
172
172
|
tourId: { type: String, default: '' },
|
|
173
173
|
/** Optional resume token `{ tourId, stepId }` (refresh / cross-app hand-off). */
|
|
174
174
|
resume: { type: Object, default: null },
|
|
175
|
+
/**
|
|
176
|
+
* Whether a first-visit tour may start on its own. The host turns it
|
|
177
|
+
* off while the user's tour is paused, so a paused tour stays hidden
|
|
178
|
+
* across page loads until the user picks "Continue".
|
|
179
|
+
*/
|
|
180
|
+
autoStart: { type: Boolean, default: true },
|
|
175
181
|
/** Stacking order of the overlay. */
|
|
176
182
|
zIndex: { type: Number, default: 10000 },
|
|
177
183
|
/** Next button label. */
|
|
@@ -571,6 +577,9 @@ export default {
|
|
|
571
577
|
this.wt.start(this.tourId)
|
|
572
578
|
return
|
|
573
579
|
}
|
|
580
|
+
if (!this.autoStart) {
|
|
581
|
+
return
|
|
582
|
+
}
|
|
574
583
|
const auto = this.wt.autoStartTour.value
|
|
575
584
|
if (!auto) {
|
|
576
585
|
return
|
|
@@ -1171,31 +1180,43 @@ export default {
|
|
|
1171
1180
|
},
|
|
1172
1181
|
|
|
1173
1182
|
/**
|
|
1174
|
-
*
|
|
1175
|
-
*
|
|
1183
|
+
* The corner close button PAUSES the tour, like ESC and the dim. It
|
|
1184
|
+
* used to complete it, and the host then wiped the saved step, so a
|
|
1185
|
+
* restart began at step 1 again. Only Finish on the last step (and a
|
|
1186
|
+
* host-supplied Skip) completes the tour; "Start over" in the user
|
|
1187
|
+
* settings stays the way back to step 1.
|
|
1176
1188
|
*
|
|
1189
|
+
* @spec openspec/changes/audit-round-lib-fixes/specs/cn-walkthrough/spec.md
|
|
1177
1190
|
* @return {void}
|
|
1178
1191
|
*/
|
|
1179
1192
|
close() {
|
|
1180
|
-
this.
|
|
1181
|
-
this.$emit('complete')
|
|
1193
|
+
this.onBackdrop()
|
|
1182
1194
|
},
|
|
1183
1195
|
|
|
1184
1196
|
/**
|
|
1185
|
-
* Pause the tour from a backdrop click or ESC. The tour
|
|
1186
|
-
* keeps its step; only
|
|
1197
|
+
* Pause the tour from the corner X, a backdrop click or ESC. The tour
|
|
1198
|
+
* hides and keeps its step; only Finish (or a host Skip) ends it.
|
|
1187
1199
|
* Pressing ESC used to dismiss it, and the host recorded that as
|
|
1188
|
-
* "seen", so the tour never came back.
|
|
1200
|
+
* "seen", so the tour never came back. The `pause` event carries
|
|
1201
|
+
* where the user was, so the host can keep a paused tour hidden on
|
|
1202
|
+
* the next page load.
|
|
1189
1203
|
*
|
|
1190
1204
|
* @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md
|
|
1205
|
+
* @spec openspec/changes/audit-round-lib-fixes/specs/cn-walkthrough/spec.md
|
|
1191
1206
|
* @return {void}
|
|
1192
1207
|
*/
|
|
1193
1208
|
onBackdrop() {
|
|
1209
|
+
const where = {
|
|
1210
|
+
tourId: (this.wt.activeTour.value && this.wt.activeTour.value.id) || '',
|
|
1211
|
+
stepId: (this.step && this.step.id) || '',
|
|
1212
|
+
index: this.index,
|
|
1213
|
+
}
|
|
1194
1214
|
this.wt.pause()
|
|
1195
1215
|
/**
|
|
1196
|
-
* @event pause Emitted when the user hides the tour (backdrop
|
|
1216
|
+
* @event pause Emitted when the user hides the tour (X, backdrop, ESC). The tour can continue later.
|
|
1217
|
+
* @type {{ tourId: string, stepId: string, index: number }}
|
|
1197
1218
|
*/
|
|
1198
|
-
this.$emit('pause')
|
|
1219
|
+
this.$emit('pause', where)
|
|
1199
1220
|
},
|
|
1200
1221
|
},
|
|
1201
1222
|
}
|