@conduction/nextcloud-vue 2.138.0 → 2.140.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/CnAppRoot/CnAppRoot.vue2.js +9 -2
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +17 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +2 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +52 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js +23 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +106 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +30 -7
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +59 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +44 -34
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +28 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js +7 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +5 -0
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +129 -6
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +2 -0
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +13 -2
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +28 -3
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +1 -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/CnRecordListWidget/CnRecordNoteRows.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js +10 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue3.js.map +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +12 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue.js +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue2.js +23 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue2.js.map +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue3.js +43 -13
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +48 -6
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/composables/useTaskInboxStore.js +4 -3
- package/dist/esm/composables/useTaskInboxStore.js.map +1 -1
- package/dist/esm/l10n/en.json.js +4 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +7 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +604 -407
- package/dist/esm/utils/builtInFormatters.js +23 -1
- package/dist/esm/utils/builtInFormatters.js.map +1 -1
- package/dist/esm/utils/fillTemplate.js +7 -1
- package/dist/esm/utils/fillTemplate.js.map +1 -1
- package/dist/esm/utils/myTeam.js +24 -4
- package/dist/esm/utils/myTeam.js.map +1 -1
- package/dist/esm/utils/resolveFilterTokens.js +5 -4
- package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
- package/dist/esm/utils/transitionInputs.js +43 -2
- package/dist/esm/utils/transitionInputs.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +932 -236
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +604 -407
- package/l10n/en.json +4 -1
- package/l10n/nl.json +7 -1
- package/package.json +1 -1
- package/src/components/CnAppRoot/CnAppRoot.vue +9 -2
- package/src/components/CnCellRenderer/CnCellRenderer.vue +19 -3
- package/src/components/CnChartWidget/CnChartWidget.md +1 -0
- package/src/components/CnChartWidget/CnChartWidget.vue +76 -1
- package/src/components/CnConversationThread/CnConversationWidget.vue +126 -1
- package/src/components/CnFactsWidget/CnFactsWidget.vue +78 -9
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +39 -1
- package/src/components/CnFilesBrowser/filesBrowser.js +7 -1
- package/src/components/CnFilesBrowser/filesBrowserColumns.js +5 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +131 -8
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +10 -2
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +28 -3
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +1 -1
- package/src/components/CnRecordListWidget/CnRecordNoteRows.vue +10 -0
- package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +68 -2
- package/src/components/CnTransitionInputFields/CnTransitionInputFields.vue +43 -1
- package/src/composables/indexSources.js +48 -6
- package/src/composables/useTaskInboxStore.js +4 -3
- package/src/css/dialog.css +18 -0
- package/src/css/look-board-detail.css +24 -0
- package/src/css/look-board-index.css +21 -0
- package/src/css/look-board.css +31 -2
- package/src/css/table.css +13 -0
- package/src/utils/builtInFormatters.js +22 -0
- package/src/utils/fillTemplate.js +7 -1
- package/src/utils/myTeam.js +24 -4
- package/src/utils/resolveFilterTokens.js +5 -4
- package/src/utils/transitionInputs.js +42 -1
|
@@ -775,6 +775,7 @@ import CnIcon from '../CnIcon/CnIcon.vue'
|
|
|
775
775
|
import { readUserPreference, writeUserPreference } from '../../composables/useUserPreferences.js'
|
|
776
776
|
import { dispatchAction } from '../../utils/actionsDispatcher.js'
|
|
777
777
|
import { fillTemplate } from '../../utils/fillTemplate.js'
|
|
778
|
+
import { readPath } from '../../utils/readPath.js'
|
|
778
779
|
import { isNewTabClick, isRowMiddleClick, preventMiddleClickAutoscroll } from '../../utils/rowAuxClick.js'
|
|
779
780
|
import { ACTIONS_NEEDING_THE_FILES_PAGE, crumbsFor, hostActionApplies, joinPath } from './filesBrowser.js'
|
|
780
781
|
import {
|
|
@@ -3049,7 +3050,7 @@ export default {
|
|
|
3049
3050
|
? { path: this.currentPath }
|
|
3050
3051
|
: { fileId: node.fileid, fileName: node.basename, path: node.path }
|
|
3051
3052
|
if (type === 'open-modal') {
|
|
3052
|
-
wrapped = { ...action, props: { ...(action.props || {}), ...context } }
|
|
3053
|
+
wrapped = { ...action, props: { ...(action.props || {}), ...context, ...this.rowPropsOf(action, node) } }
|
|
3053
3054
|
} else if (type === 'handler') {
|
|
3054
3055
|
wrapped = { ...action, args: [...(action.args || []), node ?? this.folder] }
|
|
3055
3056
|
}
|
|
@@ -3060,6 +3061,32 @@ export default {
|
|
|
3060
3061
|
dispatchAction(wrapped, { router: this.$router || null })
|
|
3061
3062
|
},
|
|
3062
3063
|
|
|
3064
|
+
/**
|
|
3065
|
+
* The clicked file's row-data fields an action asks for as modal props
|
|
3066
|
+
* (`rowProps: { prop: field }`), or none.
|
|
3067
|
+
*
|
|
3068
|
+
* @param {object} action The declared action.
|
|
3069
|
+
* @param {object|null} node The file, or null for a New-menu entry.
|
|
3070
|
+
* @return {object} The props.
|
|
3071
|
+
* @spec openspec/changes/files-review-row-when/specs/files-review-row-when/spec.md#requirement-a-modal-action-can-carry-fields-of-the-clicked-files-row-data
|
|
3072
|
+
*/
|
|
3073
|
+
rowPropsOf(action, node) {
|
|
3074
|
+
const wanted = action && action.rowProps
|
|
3075
|
+
if (node === null || !wanted || typeof wanted !== 'object') {
|
|
3076
|
+
return {}
|
|
3077
|
+
}
|
|
3078
|
+
const byId = this.resolvedRowData && typeof this.resolvedRowData === 'object' ? this.resolvedRowData : {}
|
|
3079
|
+
const entry = byId[node.fileid] ?? byId[String(node.fileid)] ?? {}
|
|
3080
|
+
const out = {}
|
|
3081
|
+
for (const [prop, field] of Object.entries(wanted)) {
|
|
3082
|
+
const value = readPath(entry, String(field))
|
|
3083
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
3084
|
+
out[prop] = value
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
return out
|
|
3088
|
+
},
|
|
3089
|
+
|
|
3063
3090
|
/**
|
|
3064
3091
|
* A click on a linked row opens the file where it lives.
|
|
3065
3092
|
*
|
|
@@ -3278,6 +3305,17 @@ export default {
|
|
|
3278
3305
|
font-size: 14px;
|
|
3279
3306
|
}
|
|
3280
3307
|
|
|
3308
|
+
/* Core's apps.css draws every dt/dd inline-block with a fixed, end-aligned dt.
|
|
3309
|
+
@spec openspec/changes/files-side-facts-core-dl/specs/files-side-facts-core-dl/spec.md#requirement-a-file-side-cards-facts-are-not-drawn-by-cores-dl-rules */
|
|
3310
|
+
.cn-files-browser__side-facts dt,
|
|
3311
|
+
.cn-files-browser__side-facts dd {
|
|
3312
|
+
display: block;
|
|
3313
|
+
width: auto;
|
|
3314
|
+
padding: 0;
|
|
3315
|
+
text-align: start;
|
|
3316
|
+
white-space: normal;
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3281
3319
|
.cn-files-browser__side-facts dt {
|
|
3282
3320
|
color: var(--color-text-maxcontrast);
|
|
3283
3321
|
}
|
|
@@ -285,13 +285,19 @@ export function indexRowData(data, { path = '', key = 'fileId' } = {}) {
|
|
|
285
285
|
* `visibleIf.extension` lists file extensions (no case, a leading dot is
|
|
286
286
|
* allowed); `visibleIf.mime` lists mime types, where one ending in `/` or
|
|
287
287
|
* `/*` names the whole family. Every condition named must hold. An action
|
|
288
|
-
* without `visibleIf` is offered on every file, as before.
|
|
288
|
+
* without `visibleIf` is offered on every file, as before. An action with
|
|
289
|
+
* `when` is offered only while `when` is `true`.
|
|
289
290
|
*
|
|
290
291
|
* @param {object} action The declared action.
|
|
291
292
|
* @param {object} node The file (`basename`, `mime`).
|
|
292
293
|
* @return {boolean} True when the action belongs on this file.
|
|
293
294
|
*/
|
|
294
295
|
export function hostActionApplies(action, node) {
|
|
296
|
+
// `when`: the action applies only while it is true (a case type flag).
|
|
297
|
+
// @spec openspec/changes/files-review-row-when/specs/files-review-row-when/spec.md#requirement-a-files-browser-entry-can-apply-only-when-a-condition-holds
|
|
298
|
+
if (action && typeof action === 'object' && 'when' in action && action.when !== true) {
|
|
299
|
+
return false
|
|
300
|
+
}
|
|
295
301
|
const condition = action && action.visibleIf
|
|
296
302
|
if (!condition || typeof condition !== 'object') {
|
|
297
303
|
return true
|
|
@@ -78,6 +78,11 @@ export function normaliseFileColumns(columns) {
|
|
|
78
78
|
if (!entry || typeof entry !== 'object' || typeof entry.key !== 'string' || entry.key === '') {
|
|
79
79
|
return
|
|
80
80
|
}
|
|
81
|
+
// `when`: the column applies only while it is true (a case type flag).
|
|
82
|
+
// @spec openspec/changes/files-review-row-when/specs/files-review-row-when/spec.md#requirement-a-files-browser-entry-can-apply-only-when-a-condition-holds
|
|
83
|
+
if ('when' in entry && entry.when !== true) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
81
86
|
if (isBuiltInFileColumn(entry.key) && entry.source === undefined) {
|
|
82
87
|
out.push({ ...BUILT_IN_FILE_COLUMNS[entry.key], ...entry, builtIn: true })
|
|
83
88
|
return
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="cn-index-page"
|
|
3
|
-
:class="[lookClass, { 'cn-index-page--with-side-panel': hasSidePanel, 'cn-index-page--quick-filters-toolbar': effectiveQuickFilterPlacement === 'toolbar' }]"
|
|
3
|
+
:class="[lookClass, { 'cn-index-page--with-side-panel': hasSidePanel, 'cn-index-page--sidebar-open': sidebarPanelOpen, 'cn-index-page--quick-filters-toolbar': effectiveQuickFilterPlacement === 'toolbar' }]"
|
|
4
4
|
data-testid="cn-index-page"
|
|
5
5
|
@keydown="onListKeydown">
|
|
6
6
|
<!-- Header — overridable via #header slot. CnPageHeader ALWAYS renders:
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
:maxVisible="quickFilterMaxVisible"
|
|
173
173
|
:fit="false"
|
|
174
174
|
:multiple="quickFilterMultiple"
|
|
175
|
-
:activeIndex="
|
|
175
|
+
:activeIndex="shownQuickFilterIndex"
|
|
176
176
|
:selectedIndices="selectedQuickFilterIndices"
|
|
177
177
|
:counts="effectiveTabCounts"
|
|
178
178
|
@update:activeIndex="onQuickFilterChange"
|
|
@@ -2240,6 +2240,21 @@ export default {
|
|
|
2240
2240
|
default: '',
|
|
2241
2241
|
},
|
|
2242
2242
|
|
|
2243
|
+
/**
|
|
2244
|
+
* Board look: the count line while a saved view is applied (manifest
|
|
2245
|
+
* `config.savedViewCountText`), a template as `countText` that may name
|
|
2246
|
+
* the view's conditions as `{view}`: its description, else its filters
|
|
2247
|
+
* in words (DqFilterInMenu "3 van 48 lopende zaken · termijn binnen 7
|
|
2248
|
+
* dagen, van mij · gesorteerd op termijn"). A view's own `countText`
|
|
2249
|
+
* override and a scope's come first.
|
|
2250
|
+
*
|
|
2251
|
+
* @spec openspec/changes/applied-view-lights-its-lens/specs/applied-view-lights-its-lens/spec.md
|
|
2252
|
+
*/
|
|
2253
|
+
savedViewCountText: {
|
|
2254
|
+
type: String,
|
|
2255
|
+
default: '',
|
|
2256
|
+
},
|
|
2257
|
+
|
|
2243
2258
|
/**
|
|
2244
2259
|
* Board look: a count line per view (manifest `config.countTextByView`),
|
|
2245
2260
|
* `{ table?, cards?, list?, board?, map? }`, each a template as
|
|
@@ -4580,6 +4595,8 @@ export default {
|
|
|
4580
4595
|
savedViewCounts: null,
|
|
4581
4596
|
// The id (or slug) of the saved view that is applied; its chip shows selected under the board look.
|
|
4582
4597
|
appliedSavedViewId: '',
|
|
4598
|
+
/** Whether the reader picked a lens chip after the applied view (then their chip shows). */
|
|
4599
|
+
lensChosenByHand: false,
|
|
4583
4600
|
// The sort option the applied view's `overrides.sortOption` selected, so leaving the view can undo it.
|
|
4584
4601
|
viewSortOption: '',
|
|
4585
4602
|
// The applied view's filters as one comparable key, so the address keeps naming the view until they change.
|
|
@@ -4653,6 +4670,8 @@ export default {
|
|
|
4653
4670
|
savedViews: [],
|
|
4654
4671
|
savedViewsLoading: false,
|
|
4655
4672
|
showSaveViewDialog: false,
|
|
4673
|
+
/** Whether the reader changed the view since it was opened or saved. */
|
|
4674
|
+
viewChanged: false,
|
|
4656
4675
|
viewPendingDelete: null,
|
|
4657
4676
|
/** An `api-call` header action waiting on its confirmation, or null. */
|
|
4658
4677
|
headerApiCallPending: null,
|
|
@@ -6419,13 +6438,53 @@ export default {
|
|
|
6419
6438
|
* @spec openspec/changes/working-list-row-actions/specs/index-page/spec.md
|
|
6420
6439
|
*/
|
|
6421
6440
|
/**
|
|
6422
|
-
* The chip
|
|
6423
|
-
*
|
|
6424
|
-
*
|
|
6441
|
+
* The lens chip an applied saved view narrows within: the non-default
|
|
6442
|
+
* tab whose every condition the view's own conditions (its filters
|
|
6443
|
+
* over its locked filters, tokens as written) hold, the most specific
|
|
6444
|
+
* first (DqFilterInMenu: "Termijn deze week" lit for the view of that
|
|
6445
|
+
* name). Null without an applied view or a fitting tab.
|
|
6446
|
+
*
|
|
6447
|
+
* @return {number|null} The tab index.
|
|
6448
|
+
* @spec openspec/changes/applied-view-lights-its-lens/specs/applied-view-lights-its-lens/spec.md
|
|
6449
|
+
*/
|
|
6450
|
+
appliedViewLensIndex() {
|
|
6451
|
+
const view = this.appliedSavedView
|
|
6452
|
+
const tabs = Array.isArray(this.tabStripEntries) ? this.tabStripEntries : []
|
|
6453
|
+
if (!view || tabs.length === 0) {
|
|
6454
|
+
return null
|
|
6455
|
+
}
|
|
6456
|
+
const query = view.query && typeof view.query === 'object' ? view.query : {}
|
|
6457
|
+
const locked = query.overrides && typeof query.overrides.lockedFilters === 'object' ? query.overrides.lockedFilters : {}
|
|
6458
|
+
const conditions = { ...(locked || {}), ...(query.filters || view.filters || {}) }
|
|
6459
|
+
const same = (a, b) => JSON.stringify(Array.isArray(a) ? a.map(String) : String(a)) === JSON.stringify(Array.isArray(b) ? b.map(String) : String(b))
|
|
6460
|
+
let best = null
|
|
6461
|
+
let bestSize = 0
|
|
6462
|
+
tabs.forEach((tab, index) => {
|
|
6463
|
+
const filter = tab && tab.filter && typeof tab.filter === 'object' ? tab.filter : {}
|
|
6464
|
+
const keys = Object.keys(filter)
|
|
6465
|
+
if (tab.default === true || keys.length === 0 || keys.length <= bestSize) {
|
|
6466
|
+
return
|
|
6467
|
+
}
|
|
6468
|
+
if (keys.every((key) => Object.hasOwn(conditions, key) && same(conditions[key], filter[key]))) {
|
|
6469
|
+
best = index
|
|
6470
|
+
bestSize = keys.length
|
|
6471
|
+
}
|
|
6472
|
+
})
|
|
6473
|
+
return best
|
|
6474
|
+
},
|
|
6475
|
+
|
|
6476
|
+
/**
|
|
6477
|
+
* The chip the strip lights: the lens an applied saved view narrows
|
|
6478
|
+
* within (until the reader picks a chip), else the active tab, else
|
|
6479
|
+
* the default tab of tabs that arrived after setup
|
|
6480
|
+
* (`quickFiltersFrom`), which is the one the fetch applies.
|
|
6425
6481
|
*
|
|
6426
6482
|
* @return {number|null} The tab index, or null without tabs.
|
|
6427
6483
|
*/
|
|
6428
6484
|
shownQuickFilterIndex() {
|
|
6485
|
+
if (!this.quickFilterMultiple && !this.lensChosenByHand && this.appliedViewLensIndex !== null) {
|
|
6486
|
+
return this.appliedViewLensIndex
|
|
6487
|
+
}
|
|
6429
6488
|
if (this.activeQuickFilterIndex !== null && this.activeQuickFilterIndex !== undefined) {
|
|
6430
6489
|
return this.activeQuickFilterIndex
|
|
6431
6490
|
}
|
|
@@ -8649,12 +8708,20 @@ export default {
|
|
|
8649
8708
|
|
|
8650
8709
|
/**
|
|
8651
8710
|
* Whether the toolbar draws Save view: not when the page switches it
|
|
8652
|
-
* off (`savedViewSave: false`) or its header carries one
|
|
8711
|
+
* off (`savedViewSave: false`) or its header carries one, and in the
|
|
8712
|
+
* board look only once the view has changed.
|
|
8653
8713
|
*
|
|
8714
|
+
* @spec openspec/changes/board-save-view-only-when-changed/specs/saved-views/spec.md#requirement-the-board-look-offers-save-view-once-the-view-has-changed
|
|
8654
8715
|
* @return {boolean}
|
|
8655
8716
|
*/
|
|
8656
8717
|
toolbarSavesView() {
|
|
8657
|
-
|
|
8718
|
+
if (this.savedViewSave === false || this.headerSavesView) {
|
|
8719
|
+
return false
|
|
8720
|
+
}
|
|
8721
|
+
// The board look offers it once the view differs from the one
|
|
8722
|
+
// opened: changed by the reader, or, with no saved view open,
|
|
8723
|
+
// filtered by the address.
|
|
8724
|
+
return !this.isBoardLook || this.viewChanged || (!this.appliedSavedViewId && this.activeFilterChips.length > 0)
|
|
8658
8725
|
},
|
|
8659
8726
|
|
|
8660
8727
|
/**
|
|
@@ -8815,6 +8882,11 @@ export default {
|
|
|
8815
8882
|
* @return {string}
|
|
8816
8883
|
*/
|
|
8817
8884
|
presentedCountText() {
|
|
8885
|
+
const viewLine = this.savedViewCountText
|
|
8886
|
+
const view = this.appliedSavedView
|
|
8887
|
+
if (view && typeof viewLine === 'string' && viewLine !== '' && this.activeScopePresentation.countText === undefined && !savedViewOverrides(view)?.countText) {
|
|
8888
|
+
return viewLine
|
|
8889
|
+
}
|
|
8818
8890
|
if (this.activeScopePresentation.countText === undefined) {
|
|
8819
8891
|
const byView = this.countTextByView
|
|
8820
8892
|
const own = byView && typeof byView === 'object' ? byView[this.currentViewMode] : undefined
|
|
@@ -8825,6 +8897,23 @@ export default {
|
|
|
8825
8897
|
return this.presented('countText')
|
|
8826
8898
|
},
|
|
8827
8899
|
|
|
8900
|
+
/**
|
|
8901
|
+
* The applied saved view's conditions for the count line's `{view}`:
|
|
8902
|
+
* its description, else its filters in words, starting lower case.
|
|
8903
|
+
*
|
|
8904
|
+
* @return {string}
|
|
8905
|
+
* @spec openspec/changes/applied-view-lights-its-lens/specs/applied-view-lights-its-lens/spec.md
|
|
8906
|
+
*/
|
|
8907
|
+
appliedViewConditionsText() {
|
|
8908
|
+
const view = this.appliedSavedView
|
|
8909
|
+
if (!view) {
|
|
8910
|
+
return ''
|
|
8911
|
+
}
|
|
8912
|
+
const own = typeof view.description === 'string' ? view.description.trim() : ''
|
|
8913
|
+
const text = own !== '' ? own : String(this.viewFilterSummary(view) || '')
|
|
8914
|
+
return text.charAt(0).toLowerCase() + text.slice(1)
|
|
8915
|
+
},
|
|
8916
|
+
|
|
8828
8917
|
headerDescriptionBase() {
|
|
8829
8918
|
const total = this.effectivePagination?.total
|
|
8830
8919
|
// Board look: the count line is a template over the rows on this page
|
|
@@ -8848,6 +8937,7 @@ export default {
|
|
|
8848
8937
|
.replace('{shown}', String(shown))
|
|
8849
8938
|
.replace('{total}', String(total))
|
|
8850
8939
|
.replace(/\{term\}/g, this.sourceTerm)
|
|
8940
|
+
.replace(/\{view\}/g, this.appliedViewConditionsText)
|
|
8851
8941
|
}
|
|
8852
8942
|
return this.countLine(this.countSubtitle, total, shown)
|
|
8853
8943
|
}
|
|
@@ -8913,6 +9003,17 @@ export default {
|
|
|
8913
9003
|
return !!this.resolvedSidebar.enabled && this.resolvedSidebar.show !== false
|
|
8914
9004
|
},
|
|
8915
9005
|
|
|
9006
|
+
/**
|
|
9007
|
+
* Whether the page's side panel is open now; the board look then lays
|
|
9008
|
+
* the header out narrower (DqZakenSorteren).
|
|
9009
|
+
*
|
|
9010
|
+
* @spec openspec/changes/board-header-buttons-under-title-beside-side-panel/specs/board-header-buttons-under-title-beside-side-panel/spec.md#requirement-the-header-buttons-sit-under-the-title-while-the-side-panel-is-open
|
|
9011
|
+
* @return {boolean}
|
|
9012
|
+
*/
|
|
9013
|
+
sidebarPanelOpen() {
|
|
9014
|
+
return Boolean(this.sidebarOpen && this.hasSidebar)
|
|
9015
|
+
},
|
|
9016
|
+
|
|
8916
9017
|
/**
|
|
8917
9018
|
* Whether the board toolbar draws the Filter button as a menu: the
|
|
8918
9019
|
* board look, `filterMenu` on, something to filter by, and no filter
|
|
@@ -8955,7 +9056,9 @@ export default {
|
|
|
8955
9056
|
|
|
8956
9057
|
/** Search props forwarded to the embedded CnIndexSidebar (defaults applied per CnIndexSidebar). */
|
|
8957
9058
|
sidebarSearchProps() {
|
|
8958
|
-
|
|
9059
|
+
// The page's own search hint, unless `sidebar.search` names one.
|
|
9060
|
+
const own = this.shownSearchPlaceholder ? { searchPlaceholder: this.shownSearchPlaceholder } : {}
|
|
9061
|
+
return { ...own, ...((this.sidebar && this.sidebar.search) || {}) }
|
|
8959
9062
|
},
|
|
8960
9063
|
|
|
8961
9064
|
/**
|
|
@@ -10756,6 +10859,7 @@ export default {
|
|
|
10756
10859
|
* @return {void}
|
|
10757
10860
|
*/
|
|
10758
10861
|
onSearchEvent(value) {
|
|
10862
|
+
this.viewChanged = true
|
|
10759
10863
|
if (this.namedSourceSearches) {
|
|
10760
10864
|
this.namedSearchTerm = value || ''
|
|
10761
10865
|
}
|
|
@@ -10775,9 +10879,11 @@ export default {
|
|
|
10775
10879
|
* @return {void}
|
|
10776
10880
|
*/
|
|
10777
10881
|
onQuickFilterChange(index) {
|
|
10882
|
+
this.viewChanged = true
|
|
10778
10883
|
// `activeQuickFilterIndex` is a setup-returned ref; the
|
|
10779
10884
|
// Vue 2 ref-unwrap proxy makes plain assignment work.
|
|
10780
10885
|
this.activeQuickFilterIndex = index
|
|
10886
|
+
this.lensChosenByHand = true
|
|
10781
10887
|
this.$emit('quick-filter-change', index)
|
|
10782
10888
|
},
|
|
10783
10889
|
|
|
@@ -10790,6 +10896,7 @@ export default {
|
|
|
10790
10896
|
* @return {void}
|
|
10791
10897
|
*/
|
|
10792
10898
|
onQuickFilterMultiChange(indices) {
|
|
10899
|
+
this.viewChanged = true
|
|
10793
10900
|
this.selectedQuickFilterIndices = Array.isArray(indices) ? indices : []
|
|
10794
10901
|
this.$emit('quick-filter-change', this.selectedQuickFilterIndices)
|
|
10795
10902
|
},
|
|
@@ -10805,6 +10912,7 @@ export default {
|
|
|
10805
10912
|
* @return {void}
|
|
10806
10913
|
*/
|
|
10807
10914
|
onSidebarSortChange(keys, value) {
|
|
10915
|
+
this.viewChanged = true
|
|
10808
10916
|
if (value !== undefined && this.selectSortOption(value)) {
|
|
10809
10917
|
return
|
|
10810
10918
|
}
|
|
@@ -10884,6 +10992,7 @@ export default {
|
|
|
10884
10992
|
* @return {void}
|
|
10885
10993
|
*/
|
|
10886
10994
|
onSortEvent(payload) {
|
|
10995
|
+
this.viewChanged = true
|
|
10887
10996
|
// An order by keys (a column header, a field in the Sort section)
|
|
10888
10997
|
// leaves an endpoint-ranked order.
|
|
10889
10998
|
if (this.sortSource.value) {
|
|
@@ -11087,6 +11196,7 @@ export default {
|
|
|
11087
11196
|
* @return {void}
|
|
11088
11197
|
*/
|
|
11089
11198
|
onClearFilters() {
|
|
11199
|
+
this.viewChanged = true
|
|
11090
11200
|
// "Clear all" on the Active line also undoes the quick filters it
|
|
11091
11201
|
// listed (a tab without an `activeLabel` is not a filter there).
|
|
11092
11202
|
for (const chip of this.quickFilterActiveChips) {
|
|
@@ -11195,6 +11305,7 @@ export default {
|
|
|
11195
11305
|
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-board-can-switch-the-field-its-columns-come-from
|
|
11196
11306
|
*/
|
|
11197
11307
|
onBoardColumnFieldChange(field) {
|
|
11308
|
+
this.viewChanged = true
|
|
11198
11309
|
this.boardColumnFieldChoice = field
|
|
11199
11310
|
/**
|
|
11200
11311
|
* @event board-column-field-change The board's column switch picked another field. Payload: the field name.
|
|
@@ -11210,6 +11321,7 @@ export default {
|
|
|
11210
11321
|
* @return {void}
|
|
11211
11322
|
*/
|
|
11212
11323
|
onBoardNarrowChange(value) {
|
|
11324
|
+
this.viewChanged = true
|
|
11213
11325
|
this.onFilterEvent({ key: this.boardNarrow.field, values: value === '' ? [] : [value] })
|
|
11214
11326
|
},
|
|
11215
11327
|
|
|
@@ -11272,6 +11384,7 @@ export default {
|
|
|
11272
11384
|
* @return {void}
|
|
11273
11385
|
*/
|
|
11274
11386
|
onFilterEvent(payload) {
|
|
11387
|
+
this.viewChanged = true
|
|
11275
11388
|
if (this.isSelfFetchMode && typeof this.list.onFilterChange === 'function') {
|
|
11276
11389
|
this.list.onFilterChange(payload.key, payload.values)
|
|
11277
11390
|
this.persistViewStateToRoute(this.currentViewState())
|
|
@@ -11294,6 +11407,7 @@ export default {
|
|
|
11294
11407
|
* @spec openspec/changes/screens-index-list-parity/specs/index-list-board-look/spec.md#requirement-the-toolbar-sits-on-the-ground-in-two-rows
|
|
11295
11408
|
*/
|
|
11296
11409
|
onRemoveActiveFilter(chip) {
|
|
11410
|
+
this.viewChanged = true
|
|
11297
11411
|
if (chip && chip.searchTerm === true) {
|
|
11298
11412
|
this.onSearchEvent('')
|
|
11299
11413
|
return
|
|
@@ -12262,6 +12376,7 @@ export default {
|
|
|
12262
12376
|
* @return {void}
|
|
12263
12377
|
*/
|
|
12264
12378
|
onColumnsEvent(columns) {
|
|
12379
|
+
this.viewChanged = true
|
|
12265
12380
|
if (this.isSelfFetchMode && this.list.visibleColumns) {
|
|
12266
12381
|
this.list.visibleColumns.value = columns
|
|
12267
12382
|
}
|
|
@@ -12309,6 +12424,7 @@ export default {
|
|
|
12309
12424
|
* @return {void}
|
|
12310
12425
|
*/
|
|
12311
12426
|
onColumnsReorder(columns) {
|
|
12427
|
+
this.viewChanged = true
|
|
12312
12428
|
this.onColumnsEvent(columns)
|
|
12313
12429
|
},
|
|
12314
12430
|
|
|
@@ -12319,6 +12435,7 @@ export default {
|
|
|
12319
12435
|
* @return {void}
|
|
12320
12436
|
*/
|
|
12321
12437
|
onPinChange(count) {
|
|
12438
|
+
this.viewChanged = true
|
|
12322
12439
|
if (!this.personalColumns || Array.isArray(this.appliedViewColumns)) {
|
|
12323
12440
|
return
|
|
12324
12441
|
}
|
|
@@ -13213,6 +13330,7 @@ export default {
|
|
|
13213
13330
|
*/
|
|
13214
13331
|
onApplySavedView(view, { keepSavedViewKey = false } = {}) {
|
|
13215
13332
|
this.appliedSavedViewId = view && (view.id || view.slug) ? String(view.id || view.slug) : ''
|
|
13333
|
+
this.lensChosenByHand = false
|
|
13216
13334
|
const state = extractViewState(view)
|
|
13217
13335
|
// A view's filters may carry tokens (`@me`, `@myTeam`): resolved here,
|
|
13218
13336
|
// and an optional one that answers nothing (no team) is dropped. A
|
|
@@ -13221,6 +13339,10 @@ export default {
|
|
|
13221
13339
|
loadMyTeam().then(() => this.onApplySavedView(view, { keepSavedViewKey }))
|
|
13222
13340
|
return
|
|
13223
13341
|
}
|
|
13342
|
+
// An opened view is unchanged until the reader changes it.
|
|
13343
|
+
this.$nextTick(() => {
|
|
13344
|
+
this.viewChanged = false
|
|
13345
|
+
})
|
|
13224
13346
|
const ctx = typeof this.selfFetchTokenCtx === 'function' ? this.selfFetchTokenCtx() : {}
|
|
13225
13347
|
state.filters = dropOptionalUnresolved(resolveFilterTokens(state.filters, ctx))
|
|
13226
13348
|
this.appliedViewFiltersKey = this.viewFiltersKey(state.filters)
|
|
@@ -13346,6 +13468,7 @@ export default {
|
|
|
13346
13468
|
}
|
|
13347
13469
|
this.savedViews = [...this.savedViews, view]
|
|
13348
13470
|
this.showSaveViewDialog = false
|
|
13471
|
+
this.viewChanged = false
|
|
13349
13472
|
this.sidebarActiveTab = 'filters-tab'
|
|
13350
13473
|
this.sidebarOpen = true
|
|
13351
13474
|
this.toastSavedView('success', t('nextcloud-vue', 'View "{name}" saved', { name }))
|
|
@@ -32,11 +32,17 @@
|
|
|
32
32
|
</div>
|
|
33
33
|
|
|
34
34
|
<div class="cn-index-sidebar__section">
|
|
35
|
+
<!-- The board look names the field by its hint, as the list's
|
|
36
|
+
own search field, with the magnifier (DqZakenSorteren). -->
|
|
35
37
|
<NcTextField
|
|
36
38
|
:modelValue="searchValue || ''"
|
|
37
39
|
:placeholder="searchPlaceholder"
|
|
38
|
-
:label="searchLabel"
|
|
39
|
-
@update:modelValue="$emit('search', $event)"
|
|
40
|
+
:label="isBoardLook ? searchPlaceholder : searchLabel"
|
|
41
|
+
@update:modelValue="$emit('search', $event)">
|
|
42
|
+
<template v-if="isBoardLook" #icon>
|
|
43
|
+
<Magnify :size="18" />
|
|
44
|
+
</template>
|
|
45
|
+
</NcTextField>
|
|
40
46
|
</div>
|
|
41
47
|
|
|
42
48
|
<!-- Sort (list, card and map views; the table sorts by its headers):
|
|
@@ -355,6 +361,7 @@ import DragVertical from 'vue-material-design-icons/DragVertical.vue'
|
|
|
355
361
|
import FilterOutline from 'vue-material-design-icons/FilterOutline.vue'
|
|
356
362
|
import FilterRemoveOutline from 'vue-material-design-icons/FilterRemoveOutline.vue'
|
|
357
363
|
import InformationOutline from 'vue-material-design-icons/InformationOutline.vue'
|
|
364
|
+
import Magnify from 'vue-material-design-icons/Magnify.vue'
|
|
358
365
|
import Pin from 'vue-material-design-icons/Pin.vue'
|
|
359
366
|
import PinOutline from 'vue-material-design-icons/PinOutline.vue'
|
|
360
367
|
import ViewColumnOutline from 'vue-material-design-icons/ViewColumnOutline.vue'
|
|
@@ -410,6 +417,7 @@ export default {
|
|
|
410
417
|
Pin,
|
|
411
418
|
PinOutline,
|
|
412
419
|
InformationOutline,
|
|
420
|
+
Magnify,
|
|
413
421
|
},
|
|
414
422
|
|
|
415
423
|
inject: {
|
|
@@ -720,6 +720,7 @@ export default {
|
|
|
720
720
|
* - `hidden` (boolean) — Hide this property
|
|
721
721
|
* - `editable` (boolean) — Override editability (default: based on schema readOnly)
|
|
722
722
|
* - `label` (string) — Override the display label
|
|
723
|
+
* - `emptyValue` (string) — Words shown, translated, for an empty or false value instead of a dash
|
|
723
724
|
* - `widget` (string) — Override the widget type for editing
|
|
724
725
|
* - `formatter` (string) — Display the value through the formatter
|
|
725
726
|
* registered under this id on CnAppRoot (`cnFormatters`), called as
|
|
@@ -739,7 +740,8 @@ export default {
|
|
|
739
740
|
},
|
|
740
741
|
|
|
741
742
|
/**
|
|
742
|
-
* Number of grid columns.
|
|
743
|
+
* Number of grid columns. The board look fits 200px columns instead,
|
|
744
|
+
* except for one column, which it keeps.
|
|
743
745
|
*/
|
|
744
746
|
columns: {
|
|
745
747
|
type: Number,
|
|
@@ -1100,7 +1102,8 @@ export default {
|
|
|
1100
1102
|
// still showing the stored code — `submitted` under a Dutch
|
|
1101
1103
|
// label, beside a list that already read "Ingediend".
|
|
1102
1104
|
const enumLabel = this.enumDisplayLabel(field, raw)
|
|
1103
|
-
|
|
1105
|
+
const empty = this.emptyValueFor(field, raw)
|
|
1106
|
+
values[field.key] = empty !== null ? empty : (enumLabel !== null ? enumLabel : formatValue(raw, prop || {}))
|
|
1104
1107
|
}
|
|
1105
1108
|
return values
|
|
1106
1109
|
},
|
|
@@ -1116,8 +1119,12 @@ export default {
|
|
|
1116
1119
|
* CSS grid template for the container.
|
|
1117
1120
|
*/
|
|
1118
1121
|
gridStyle() {
|
|
1119
|
-
// The board look: as many 200px columns as the card has room for
|
|
1122
|
+
// The board look: as many 200px columns as the card has room for,
|
|
1123
|
+
// unless the config asks for one column (a stacked list of pairs).
|
|
1120
1124
|
if (normalizeLook(this.cnLook) === 'board') {
|
|
1125
|
+
if (this.columns === 1) {
|
|
1126
|
+
return { 'grid-template-columns': 'minmax(0, 1fr)' }
|
|
1127
|
+
}
|
|
1121
1128
|
return {
|
|
1122
1129
|
'grid-template-columns': 'repeat(auto-fit, minmax(200px, 1fr))',
|
|
1123
1130
|
}
|
|
@@ -1842,6 +1849,24 @@ export default {
|
|
|
1842
1849
|
return this.isPlainObject(raw)
|
|
1843
1850
|
},
|
|
1844
1851
|
|
|
1852
|
+
/**
|
|
1853
|
+
* The words an override gives an empty or false value
|
|
1854
|
+
* (`overrides[key].emptyValue`, translated), or null to format it as usual.
|
|
1855
|
+
*
|
|
1856
|
+
* @param {object} field - Resolved field definition from resolvedFields
|
|
1857
|
+
* @param {*} raw - The field's value
|
|
1858
|
+
* @return {string|null}
|
|
1859
|
+
* @spec openspec/changes/data-widget-empty-value-one-column/specs/data-widget/spec.md
|
|
1860
|
+
*/
|
|
1861
|
+
emptyValueFor(field, raw) {
|
|
1862
|
+
const override = this.resolvedOverrides[field.key]
|
|
1863
|
+
const words = override && typeof override.emptyValue === 'string' ? override.emptyValue : ''
|
|
1864
|
+
if (words === '' || !(raw === null || raw === undefined || raw === '' || raw === false)) {
|
|
1865
|
+
return null
|
|
1866
|
+
}
|
|
1867
|
+
return this.cnTranslate(words)
|
|
1868
|
+
},
|
|
1869
|
+
|
|
1845
1870
|
/**
|
|
1846
1871
|
* Check if a field is editable.
|
|
1847
1872
|
*
|
|
@@ -860,7 +860,7 @@ export default {
|
|
|
860
860
|
// `secondary` (a second, muted line under the cell) rides
|
|
861
861
|
// along too: the table draws it, and dropping it here took the
|
|
862
862
|
// list rows' second line away (zuiddrecht-pixel-gaps-3).
|
|
863
|
-
for (const k of ['format', 'widget', 'widgetProps', 'formatter', 'align', 'width', 'type', 'enum', 'enumLabels', 'sortable', 'secondary', 'colorMap', 'grow']) {
|
|
863
|
+
for (const k of ['format', 'widget', 'widgetProps', 'formatter', 'align', 'width', 'type', 'enum', 'enumLabels', 'sortable', 'secondary', 'colorMap', 'grow', 'cellClass']) {
|
|
864
864
|
if (c[k] !== undefined) {
|
|
865
865
|
out[k] = c[k]
|
|
866
866
|
}
|
|
@@ -117,6 +117,13 @@ import { readPath } from '../../utils/readPath.js'
|
|
|
117
117
|
/** The bus channel every endpoint-bound widget on the page refetches on. */
|
|
118
118
|
const PAGE_REFRESH_CHANNEL = 'cn:page:refresh'
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* The document event a recorded note sends, so a row's leaf (humaniq's
|
|
122
|
+
* hours) can record what it holds for the same object at the same moment.
|
|
123
|
+
* `detail` is the row's leaf props plus `note`.
|
|
124
|
+
*/
|
|
125
|
+
const NOTE_RECORDED_EVENT = 'cn-record-notes:recorded'
|
|
126
|
+
|
|
120
127
|
/**
|
|
121
128
|
* The rows of a record list drawn as notes to record (`presentation:
|
|
122
129
|
* "notes"`, DqDagAfsluiten "Nog open van vandaag"): per row its pill, title,
|
|
@@ -351,6 +358,9 @@ export default {
|
|
|
351
358
|
try {
|
|
352
359
|
const { default: axios } = await import('@nextcloud/axios')
|
|
353
360
|
await axios.post(prefixUrl(url), { [this.action.bodyField || 'message']: text })
|
|
361
|
+
if (this.leaf) {
|
|
362
|
+
document.dispatchEvent(new CustomEvent(NOTE_RECORDED_EVENT, { detail: { ...this.leafProps(item.row), note: text } }))
|
|
363
|
+
}
|
|
354
364
|
const { [item.key]: done, ...rest } = this.drafts
|
|
355
365
|
this.drafts = rest
|
|
356
366
|
if (refresh) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
SPDX-License-Identifier: EUPL-1.2
|
|
4
4
|
-->
|
|
5
5
|
<template>
|
|
6
|
-
<div class="cn-stacked-bar" :class="{ 'cn-stacked-bar--inset': inset }" data-testid="cn-stacked-bar">
|
|
6
|
+
<div class="cn-stacked-bar" :class="{ 'cn-stacked-bar--inset': inset, 'cn-stacked-bar--compact': compact }" data-testid="cn-stacked-bar">
|
|
7
7
|
<div v-if="isLoading" class="cn-stacked-bar__state" role="status">
|
|
8
8
|
<NcLoadingIcon :size="20" />
|
|
9
9
|
<span>{{ loadingLabel }}</span>
|
|
@@ -183,7 +183,7 @@ export default {
|
|
|
183
183
|
* segments to the card (`header` event, `count`), for a chip after the
|
|
184
184
|
* title or a `{count}` in it.
|
|
185
185
|
*
|
|
186
|
-
* @type {{inset?: boolean, headerCount?: 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}}
|
|
186
|
+
* @type {{inset?: boolean, compact?: boolean, headerCount?: 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}}
|
|
187
187
|
*/
|
|
188
188
|
content: {
|
|
189
189
|
type: Object,
|
|
@@ -241,6 +241,17 @@ export default {
|
|
|
241
241
|
return Boolean(this.content && this.content.inset === true)
|
|
242
242
|
},
|
|
243
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Whether the widget is the compact summary box (`content.compact`):
|
|
246
|
+
* a 15px heading, one thin bar and the legend on one line.
|
|
247
|
+
*
|
|
248
|
+
* @spec openspec/changes/stacked-bar-compact/specs/stacked-bar-compact/spec.md#requirement-a-stacked-bar-can-be-drawn-as-the-compact-summary-box
|
|
249
|
+
* @return {boolean}
|
|
250
|
+
*/
|
|
251
|
+
compact() {
|
|
252
|
+
return Boolean(this.content && this.content.compact === true)
|
|
253
|
+
},
|
|
254
|
+
|
|
244
255
|
/**
|
|
245
256
|
* The translate function in use.
|
|
246
257
|
*
|
|
@@ -651,4 +662,59 @@ export default {
|
|
|
651
662
|
line-height: 1.2;
|
|
652
663
|
color: var(--color-main-text);
|
|
653
664
|
}
|
|
665
|
+
|
|
666
|
+
/* `content.compact: true`: the summary box (DqZaakDocumenten "4 van 7
|
|
667
|
+
beoordeeld"): the sunken ground, a 15px heading, one 8px bar of joined
|
|
668
|
+
segments and the legend on one line, each count beside its label. */
|
|
669
|
+
.cn-stacked-bar--compact {
|
|
670
|
+
box-sizing: border-box;
|
|
671
|
+
gap: 10px;
|
|
672
|
+
padding: 14px 16px;
|
|
673
|
+
border-radius: 10px;
|
|
674
|
+
background: var(--cn-board-sunken-ground, var(--color-background-hover));
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.cn-stacked-bar--compact .cn-stacked-bar__heading {
|
|
678
|
+
flex-wrap: wrap;
|
|
679
|
+
gap: 8px;
|
|
680
|
+
font-size: 15px;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.cn-stacked-bar--compact .cn-stacked-bar__bar {
|
|
684
|
+
gap: 0;
|
|
685
|
+
height: 8px;
|
|
686
|
+
border-radius: 4px;
|
|
687
|
+
overflow: hidden;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.cn-stacked-bar--compact .cn-stacked-bar__segment {
|
|
691
|
+
border-radius: 0;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.cn-stacked-bar--compact .cn-stacked-bar__legend {
|
|
695
|
+
display: flex;
|
|
696
|
+
flex-wrap: wrap;
|
|
697
|
+
gap: 8px 18px;
|
|
698
|
+
font-size: 14px;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.cn-stacked-bar--compact .cn-stacked-bar__legend-item {
|
|
702
|
+
flex-direction: row;
|
|
703
|
+
align-items: center;
|
|
704
|
+
gap: 8px;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.cn-stacked-bar--compact .cn-stacked-bar__label {
|
|
708
|
+
color: var(--color-main-text);
|
|
709
|
+
font-size: 1em;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.cn-stacked-bar--compact .cn-stacked-bar__dot {
|
|
713
|
+
border-radius: 50%;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.cn-stacked-bar--compact .cn-stacked-bar__count {
|
|
717
|
+
font-size: 1em;
|
|
718
|
+
line-height: inherit;
|
|
719
|
+
}
|
|
654
720
|
</style>
|