@conduction/nextcloud-vue 2.124.0 → 2.125.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/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +120 -11
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +78 -32
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +8 -7
- 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/CnAssignDialog/CnAssignDialog.vue.js +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +2 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js +2 -2
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue2.js +5 -0
- package/dist/esm/components/CnDialog/CnDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue3.js +1 -1
- package/dist/esm/components/CnDialog/CnDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +13 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +7 -2
- 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/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +159 -10
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +151 -90
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +12 -0
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js +39 -68
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js +70 -116
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +19 -3
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +8 -8
- package/dist/esm/l10n/nl.json.js +8 -8
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +316 -185
- package/dist/nextcloud-vue.cjs.js +1149 -808
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +316 -185
- package/l10n/en.json +8 -8
- package/l10n/nl.json +8 -8
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +173 -14
- package/src/components/CnAppRoot/CnAppRoot.vue +8 -7
- package/src/components/CnAssignDialog/CnAssignDialog.vue +4 -3
- package/src/components/CnDialog/CnDialog.vue +6 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +14 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +7 -2
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +237 -23
- package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +13 -1
- package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +147 -145
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +19 -3
- package/src/css/dialog.css +23 -0
- package/src/css/look-board-index.css +5 -1
- package/src/css/look-board.css +19 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<template>
|
|
7
7
|
<div
|
|
8
8
|
class="cn-record-list"
|
|
9
|
-
:class="`cn-record-list--${presentation}
|
|
9
|
+
:class="[`cn-record-list--${presentation}`, { 'cn-record-list--compact': content.density === 'compact' }]"
|
|
10
10
|
data-testid="cn-record-list">
|
|
11
11
|
<p v-if="intro && !absent" class="cn-record-list__intro" data-testid="cn-record-list-intro">
|
|
12
12
|
{{ intro }}
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
</p>
|
|
41
41
|
</div>
|
|
42
42
|
<!-- table: one row per record under a header, one cell per `columns`
|
|
43
|
-
entry; a cell past its `alertAbove` reads bold in the danger colour
|
|
43
|
+
entry; a cell past its `alertAbove` reads bold in the danger colour,
|
|
44
|
+
a `tone` cell is a toned label, a `sortable` header sorts the rows. -->
|
|
44
45
|
<table v-else-if="presentation === 'table'" class="cn-record-list__table" data-testid="cn-record-list-table">
|
|
45
46
|
<thead>
|
|
46
47
|
<tr>
|
|
@@ -48,18 +49,41 @@
|
|
|
48
49
|
v-for="col in tableColumns"
|
|
49
50
|
:key="col.key"
|
|
50
51
|
scope="col"
|
|
52
|
+
:aria-sort="col.sortable ? sortStateOf(col.key) : undefined"
|
|
51
53
|
:class="{ 'cn-record-list__cell--end': col.align === 'end' }">
|
|
52
|
-
|
|
54
|
+
<button
|
|
55
|
+
v-if="col.sortable"
|
|
56
|
+
type="button"
|
|
57
|
+
class="cn-record-list__sort"
|
|
58
|
+
:data-testid="`cn-record-list-sort-${col.key}`"
|
|
59
|
+
@click="toggleTableSort(col.key)">
|
|
60
|
+
{{ col.label }}
|
|
61
|
+
<span class="cn-record-list__sort-mark" aria-hidden="true">{{ sortMarkOf(col.key) }}</span>
|
|
62
|
+
</button>
|
|
63
|
+
<template v-else>
|
|
64
|
+
{{ col.label }}
|
|
65
|
+
</template>
|
|
53
66
|
</th>
|
|
54
67
|
</tr>
|
|
55
68
|
</thead>
|
|
56
69
|
<tbody>
|
|
57
70
|
<tr v-for="item in tableRows" :key="item.key" data-testid="cn-record-list-item">
|
|
58
71
|
<td
|
|
59
|
-
v-for="cell in item.cells"
|
|
72
|
+
v-for="(cell, cellIndex) in item.cells"
|
|
60
73
|
:key="cell.key"
|
|
74
|
+
:style="cellIndex === 0 && item.depth > 0 ? `padding-inline-start: calc(${item.depth} * 16px)` : undefined"
|
|
61
75
|
:class="{ 'cn-record-list__cell--end': cell.align === 'end', 'cn-record-list__cell--alert': cell.alert }">
|
|
62
|
-
|
|
76
|
+
<CnStatusBadge
|
|
77
|
+
v-if="cell.tone"
|
|
78
|
+
:label="cell.text"
|
|
79
|
+
:variant="cell.tone"
|
|
80
|
+
size="small" />
|
|
81
|
+
<router-link v-else-if="cellIndex === 0 && item.to" :to="item.to">
|
|
82
|
+
{{ cell.text }}
|
|
83
|
+
</router-link>
|
|
84
|
+
<template v-else>
|
|
85
|
+
{{ cell.text }}
|
|
86
|
+
</template>
|
|
63
87
|
</td>
|
|
64
88
|
</tr>
|
|
65
89
|
</tbody>
|
|
@@ -200,17 +224,25 @@
|
|
|
200
224
|
:size="18"
|
|
201
225
|
aria-hidden="true" />
|
|
202
226
|
<NcActions
|
|
203
|
-
v-if="item.tag === 'div' && rowActions.length > 0"
|
|
227
|
+
v-if="item.tag === 'div' && item.rowActions.length > 0"
|
|
204
228
|
:aria-label="rowActionsLabel"
|
|
205
229
|
data-testid="cn-record-list-row-actions">
|
|
206
|
-
<
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
230
|
+
<template v-for="entry in item.rowActions" :key="`row-action-${entry.index}`">
|
|
231
|
+
<NcActionLink
|
|
232
|
+
v-if="entry.href"
|
|
233
|
+
:href="entry.href"
|
|
234
|
+
:target="entry.external ? '_blank' : undefined"
|
|
235
|
+
:data-testid="`cn-record-list-row-action-${entry.index}`">
|
|
236
|
+
{{ entry.action.label }}
|
|
237
|
+
</NcActionLink>
|
|
238
|
+
<NcActionButton
|
|
239
|
+
v-else
|
|
240
|
+
:closeAfterClick="true"
|
|
241
|
+
:data-testid="`cn-record-list-row-action-${entry.index}`"
|
|
242
|
+
@click="runRowActionEntry(entry.action, item.row)">
|
|
243
|
+
{{ entry.action.label }}
|
|
244
|
+
</NcActionButton>
|
|
245
|
+
</template>
|
|
214
246
|
</NcActions>
|
|
215
247
|
</component>
|
|
216
248
|
|
|
@@ -327,7 +359,7 @@
|
|
|
327
359
|
<script>
|
|
328
360
|
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
|
|
329
361
|
import { translate as t } from '@nextcloud/l10n'
|
|
330
|
-
import { NcActionButton, NcActions, NcButton, NcLoadingIcon } from '@nextcloud/vue'
|
|
362
|
+
import { NcActionButton, NcActionLink, NcActions, NcButton, NcLoadingIcon } from '@nextcloud/vue'
|
|
331
363
|
import { inject, ref } from 'vue'
|
|
332
364
|
import ChevronRight from 'vue-material-design-icons/ChevronRight.vue'
|
|
333
365
|
import CnIcon from '../CnIcon/CnIcon.vue'
|
|
@@ -346,7 +378,7 @@ import { lensUnavailableText, readLensReports } from '../../utils/lensAvailabili
|
|
|
346
378
|
import { pageFilter, pageSort } from '../../utils/pageControls.js'
|
|
347
379
|
import { readPath } from '../../utils/readPath.js'
|
|
348
380
|
import { dropOptionalUnresolved, hasUnresolvedTokens, resolveDeepTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'
|
|
349
|
-
import { evaluateVisibleWhen } from '../../utils/visibleWhen.js'
|
|
381
|
+
import { evaluateVisibleWhen, evaluateVisibleWhenLocal } from '../../utils/visibleWhen.js'
|
|
350
382
|
|
|
351
383
|
const PAGE_REFRESH_CHANNEL = 'cn:page:refresh'
|
|
352
384
|
|
|
@@ -354,6 +386,22 @@ const PAGE_REFRESH_CHANNEL = 'cn:page:refresh'
|
|
|
354
386
|
let footerSeq = 0
|
|
355
387
|
const PRESENTATIONS = ['rows', 'feed', 'inline', 'cards', 'notice', 'table', 'notes']
|
|
356
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Compare two table cell texts: as numbers when both read as one, else as text.
|
|
391
|
+
*
|
|
392
|
+
* @param {string} a One cell text.
|
|
393
|
+
* @param {string} b The other.
|
|
394
|
+
* @return {number} Negative, zero or positive.
|
|
395
|
+
*/
|
|
396
|
+
function compareCells(a, b) {
|
|
397
|
+
const x = Number(a)
|
|
398
|
+
const y = Number(b)
|
|
399
|
+
if (a !== '' && b !== '' && Number.isFinite(x) && Number.isFinite(y)) {
|
|
400
|
+
return x - y
|
|
401
|
+
}
|
|
402
|
+
return String(a).localeCompare(String(b))
|
|
403
|
+
}
|
|
404
|
+
|
|
357
405
|
/** The tones a `notice` list takes. */
|
|
358
406
|
const NOTICE_VARIANTS = ['info', 'warning', 'error']
|
|
359
407
|
|
|
@@ -405,7 +453,7 @@ function unwrap(value) {
|
|
|
405
453
|
export default {
|
|
406
454
|
name: 'CnRecordListWidget',
|
|
407
455
|
|
|
408
|
-
components: { ChevronRight, CnIcon, CnRecordNoteRows, CnStatusBadge, NcActionButton, NcActions, NcButton, NcLoadingIcon },
|
|
456
|
+
components: { ChevronRight, CnIcon, CnRecordNoteRows, CnStatusBadge, NcActionButton, NcActionLink, NcActions, NcButton, NcLoadingIcon },
|
|
409
457
|
|
|
410
458
|
inject: {
|
|
411
459
|
/** Detail-page object context (`{ objectId, object, register, schema }`). */
|
|
@@ -451,6 +499,8 @@ export default {
|
|
|
451
499
|
* per value, headed by the field's `valueLabels` entry; `groupOrder`
|
|
452
500
|
* (values) orders the groups and `groupEmptyLabel` heads the rows
|
|
453
501
|
* without a value.
|
|
502
|
+
* `density: "compact"` draws the rows 10px above and below, at least
|
|
503
|
+
* 56px tall, with the title at 500 (DqProcesanalyse).
|
|
454
504
|
*
|
|
455
505
|
* @type {object}
|
|
456
506
|
*/
|
|
@@ -501,6 +551,8 @@ export default {
|
|
|
501
551
|
|
|
502
552
|
data() {
|
|
503
553
|
return {
|
|
554
|
+
/** The reader's sort of a `table`: the column key and `ascending` or `descending`. */
|
|
555
|
+
tableSort: { key: '', dir: '' },
|
|
504
556
|
rows: [],
|
|
505
557
|
total: 0,
|
|
506
558
|
loading: false,
|
|
@@ -702,6 +754,7 @@ export default {
|
|
|
702
754
|
dot: this.dotOf(row),
|
|
703
755
|
flag: this.flagOf(row),
|
|
704
756
|
links: this.linksOf(row),
|
|
757
|
+
rowActions: this.rowActionsOf(row),
|
|
705
758
|
}
|
|
706
759
|
})
|
|
707
760
|
},
|
|
@@ -780,8 +833,11 @@ export default {
|
|
|
780
833
|
* @spec openspec/changes/record-list-table/specs/record-list-table/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-small-table
|
|
781
834
|
*/
|
|
782
835
|
tableRows() {
|
|
783
|
-
|
|
836
|
+
const indentPath = this.content?.indentPath
|
|
837
|
+
const rows = this.items.map((item) => ({
|
|
784
838
|
key: item.key,
|
|
839
|
+
to: item.attrs.to || null,
|
|
840
|
+
depth: indentPath ? Math.max(0, Math.floor(Number(readPath(item.row, indentPath)) || 0)) : 0,
|
|
785
841
|
cells: this.tableColumns.map((col) => {
|
|
786
842
|
const text = this.fill(col.value, item.row)
|
|
787
843
|
const limit = Number(col.alertAbove)
|
|
@@ -791,9 +847,17 @@ export default {
|
|
|
791
847
|
text,
|
|
792
848
|
align: col.align,
|
|
793
849
|
alert: col.alertAbove !== undefined && Number.isFinite(limit) && text !== '' && Number.isFinite(value) && value > limit,
|
|
850
|
+
tone: this.cellToneOf(col, item.row, text),
|
|
794
851
|
}
|
|
795
852
|
}),
|
|
796
853
|
}))
|
|
854
|
+
const { key, dir } = this.tableSort
|
|
855
|
+
const index = this.tableColumns.findIndex((col) => col.key === key)
|
|
856
|
+
if (index < 0 || !dir) {
|
|
857
|
+
return rows
|
|
858
|
+
}
|
|
859
|
+
const sign = dir === 'descending' ? -1 : 1
|
|
860
|
+
return [...rows].sort((a, b) => sign * compareCells(a.cells[index].text, b.cells[index].text))
|
|
797
861
|
},
|
|
798
862
|
|
|
799
863
|
/** @return {string} The note under the list (`footnote`), translated. */
|
|
@@ -1455,6 +1519,123 @@ export default {
|
|
|
1455
1519
|
}
|
|
1456
1520
|
},
|
|
1457
1521
|
|
|
1522
|
+
/**
|
|
1523
|
+
* The badge variant of a `table` cell with a `tone`
|
|
1524
|
+
* (`{ field?, map, default?, override?: { when, tone } }`): the value at
|
|
1525
|
+
* `field` (else the cell text) looked up in `map`, else `default`. While
|
|
1526
|
+
* `override.when` (a condition over the row) holds, the cell takes
|
|
1527
|
+
* `override.tone` instead, so a verdict is never green unless a second
|
|
1528
|
+
* field allows it.
|
|
1529
|
+
*
|
|
1530
|
+
* @param {object} col The column.
|
|
1531
|
+
* @param {object} row The row.
|
|
1532
|
+
* @param {string} text The cell text.
|
|
1533
|
+
* @return {string} A badge variant, or '' for a plain cell.
|
|
1534
|
+
* @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows
|
|
1535
|
+
*/
|
|
1536
|
+
cellToneOf(col, row, text) {
|
|
1537
|
+
const tone = col.tone
|
|
1538
|
+
if (!tone || typeof tone !== 'object') {
|
|
1539
|
+
return ''
|
|
1540
|
+
}
|
|
1541
|
+
let variant
|
|
1542
|
+
if (tone.override && typeof tone.override === 'object' && evaluateVisibleWhenLocal(tone.override.when, row || {})) {
|
|
1543
|
+
variant = tone.override.tone
|
|
1544
|
+
} else {
|
|
1545
|
+
const value = tone.field ? readPath(row, tone.field) : text
|
|
1546
|
+
const map = tone.map && typeof tone.map === 'object' ? tone.map : {}
|
|
1547
|
+
variant = Object.hasOwn(map, String(value)) ? map[String(value)] : tone.default
|
|
1548
|
+
}
|
|
1549
|
+
return isBadgeVariant(variant) ? variant : 'default'
|
|
1550
|
+
},
|
|
1551
|
+
|
|
1552
|
+
/**
|
|
1553
|
+
* The `aria-sort` of a sortable `table` column.
|
|
1554
|
+
*
|
|
1555
|
+
* @param {string} key The column key.
|
|
1556
|
+
* @return {string} `ascending`, `descending` or `none`.
|
|
1557
|
+
*/
|
|
1558
|
+
sortStateOf(key) {
|
|
1559
|
+
return this.tableSort.key === key && this.tableSort.dir ? this.tableSort.dir : 'none'
|
|
1560
|
+
},
|
|
1561
|
+
|
|
1562
|
+
/**
|
|
1563
|
+
* The arrow after a sortable column's label.
|
|
1564
|
+
*
|
|
1565
|
+
* @param {string} key The column key.
|
|
1566
|
+
* @return {string} An up or down arrow, or '' while the column is not the sort.
|
|
1567
|
+
*/
|
|
1568
|
+
sortMarkOf(key) {
|
|
1569
|
+
const state = this.sortStateOf(key)
|
|
1570
|
+
if (state === 'ascending') {
|
|
1571
|
+
return '▲'
|
|
1572
|
+
}
|
|
1573
|
+
return state === 'descending' ? '▼' : ''
|
|
1574
|
+
},
|
|
1575
|
+
|
|
1576
|
+
/**
|
|
1577
|
+
* Sort the `table` by a column: ascending first, then descending.
|
|
1578
|
+
*
|
|
1579
|
+
* @param {string} key The column key.
|
|
1580
|
+
* @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows
|
|
1581
|
+
*/
|
|
1582
|
+
toggleTableSort(key) {
|
|
1583
|
+
const dir = this.tableSort.key === key && this.tableSort.dir === 'ascending' ? 'descending' : 'ascending'
|
|
1584
|
+
this.tableSort = { key, dir }
|
|
1585
|
+
},
|
|
1586
|
+
|
|
1587
|
+
/**
|
|
1588
|
+
* The rows of a read with `flattenPath` set: each entry of the list at
|
|
1589
|
+
* that path on a record becomes a row, with the record at `@parent`.
|
|
1590
|
+
* A record without the list adds no row. Without `flattenPath` the
|
|
1591
|
+
* records are the rows.
|
|
1592
|
+
*
|
|
1593
|
+
* @param {Array<object>} records The records read.
|
|
1594
|
+
* @return {Array<object>} The rows.
|
|
1595
|
+
* @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows
|
|
1596
|
+
*/
|
|
1597
|
+
flattenRows(records) {
|
|
1598
|
+
const path = this.content?.flattenPath
|
|
1599
|
+
if (typeof path !== 'string' || path === '') {
|
|
1600
|
+
return records
|
|
1601
|
+
}
|
|
1602
|
+
return records.flatMap((record) => {
|
|
1603
|
+
const list = readPath(record, path)
|
|
1604
|
+
return Array.isArray(list)
|
|
1605
|
+
? list.filter((entry) => entry && typeof entry === 'object').map((entry) => ({ ...entry, '@parent': record }))
|
|
1606
|
+
: []
|
|
1607
|
+
})
|
|
1608
|
+
},
|
|
1609
|
+
|
|
1610
|
+
/**
|
|
1611
|
+
* The row actions shown on one row: those whose `visibleWhen` (a
|
|
1612
|
+
* condition over the row) holds. An `href` action is a template over
|
|
1613
|
+
* the row and shows only when it fills to a web address or an
|
|
1614
|
+
* instance path; a web address opens in a new tab.
|
|
1615
|
+
*
|
|
1616
|
+
* @param {object} row The row.
|
|
1617
|
+
* @return {Array<{action: object, index: number, href: string, external: boolean}>} The visible actions, with their place in `rowActions`.
|
|
1618
|
+
* @spec openspec/changes/record-list-row-rules/specs/record-list-row-rules/spec.md#requirement-a-row-action-can-depend-on-the-row
|
|
1619
|
+
*/
|
|
1620
|
+
rowActionsOf(row) {
|
|
1621
|
+
const shown = []
|
|
1622
|
+
this.rowActions.forEach((action, index) => {
|
|
1623
|
+
if (action.visibleWhen && !evaluateVisibleWhenLocal(action.visibleWhen, row || {})) {
|
|
1624
|
+
return
|
|
1625
|
+
}
|
|
1626
|
+
if (typeof action.href !== 'string') {
|
|
1627
|
+
shown.push({ action, index, href: '', external: false })
|
|
1628
|
+
return
|
|
1629
|
+
}
|
|
1630
|
+
const href = this.fill(action.href, row).trim()
|
|
1631
|
+
const external = /^https?:\/\//i.test(href)
|
|
1632
|
+
if (external || (href.startsWith('/') && !href.startsWith('//'))) {
|
|
1633
|
+
shown.push({ action, index, href, external })
|
|
1634
|
+
}
|
|
1635
|
+
})
|
|
1636
|
+
return shown
|
|
1637
|
+
},
|
|
1638
|
+
|
|
1458
1639
|
/**
|
|
1459
1640
|
* A row's `links` line: the ids at `links.field`, each labelled from
|
|
1460
1641
|
* `links.labelSource` (`{ register, schema, template }`) once read, else
|
|
@@ -1782,7 +1963,7 @@ export default {
|
|
|
1782
1963
|
* @spec openspec/changes/endpoint-source-card-grid-record-list/specs/dashboard-page/spec.md#requirement-a-record-list-and-a-card-grid-can-read-an-endpoint
|
|
1783
1964
|
*/
|
|
1784
1965
|
takeEndpointRows() {
|
|
1785
|
-
this.rows = Array.isArray(this.epData) ? this.epData : []
|
|
1966
|
+
this.rows = this.flattenRows(Array.isArray(this.epData) ? this.epData : [])
|
|
1786
1967
|
this.total = this.rows.length
|
|
1787
1968
|
this.loading = this.epLoading === true
|
|
1788
1969
|
this.error = Boolean(this.epError)
|
|
@@ -1859,14 +2040,14 @@ export default {
|
|
|
1859
2040
|
if (run !== this.fetchRun) {
|
|
1860
2041
|
return
|
|
1861
2042
|
}
|
|
1862
|
-
this.rows = ranked.rows
|
|
1863
|
-
this.total = ranked.total
|
|
2043
|
+
this.rows = this.flattenRows(ranked.rows)
|
|
2044
|
+
this.total = this.content?.flattenPath ? this.rows.length : ranked.total
|
|
1864
2045
|
return
|
|
1865
2046
|
}
|
|
1866
2047
|
const response = await axios.get(url, { params })
|
|
1867
2048
|
const data = response && response.data ? response.data : {}
|
|
1868
|
-
this.rows = Array.isArray(data.results) ? data.results : []
|
|
1869
|
-
this.total = typeof data.total === 'number' ? data.total : this.rows.length
|
|
2049
|
+
this.rows = this.flattenRows(Array.isArray(data.results) ? data.results : [])
|
|
2050
|
+
this.total = typeof data.total === 'number' && !this.content?.flattenPath ? data.total : this.rows.length
|
|
1870
2051
|
this.lenses = readLensReports(data)
|
|
1871
2052
|
} catch (e) {
|
|
1872
2053
|
// eslint-disable-next-line no-console
|
|
@@ -2031,6 +2212,16 @@ export default {
|
|
|
2031
2212
|
font-weight: 700;
|
|
2032
2213
|
}
|
|
2033
2214
|
|
|
2215
|
+
.cn-record-list--compact .cn-record-list__row {
|
|
2216
|
+
box-sizing: border-box;
|
|
2217
|
+
min-height: 56px;
|
|
2218
|
+
padding: 10px 0;
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
.cn-record-list--compact .cn-record-list__title {
|
|
2222
|
+
font-weight: 500;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2034
2225
|
.cn-record-list__meta {
|
|
2035
2226
|
color: var(--color-text-maxcontrast);
|
|
2036
2227
|
font-size: 13px;
|
|
@@ -2077,6 +2268,29 @@ export default {
|
|
|
2077
2268
|
border-bottom: 1px solid var(--color-border);
|
|
2078
2269
|
}
|
|
2079
2270
|
|
|
2271
|
+
.cn-record-list__sort {
|
|
2272
|
+
display: inline-flex;
|
|
2273
|
+
gap: 4px;
|
|
2274
|
+
align-items: center;
|
|
2275
|
+
min-height: 0;
|
|
2276
|
+
margin: 0;
|
|
2277
|
+
padding: 0;
|
|
2278
|
+
border: none;
|
|
2279
|
+
background: none;
|
|
2280
|
+
color: inherit;
|
|
2281
|
+
font: inherit;
|
|
2282
|
+
cursor: pointer;
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
.cn-record-list__sort:focus-visible {
|
|
2286
|
+
outline: 2px solid var(--color-primary-element);
|
|
2287
|
+
outline-offset: 2px;
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
.cn-record-list__sort-mark {
|
|
2291
|
+
font-size: 10px;
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2080
2294
|
.cn-record-list__table .cn-record-list__cell--end {
|
|
2081
2295
|
padding-inline-start: 12px;
|
|
2082
2296
|
text-align: end;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
sidebar's Filters tab (CnSavedViewsPanel).
|
|
11
11
|
-->
|
|
12
12
|
<div
|
|
13
|
-
v-if="isBoardLook && chipRows.length > 0"
|
|
13
|
+
v-if="isBoardLook && chips && chipRows.length > 0"
|
|
14
14
|
class="cn-saved-views__chips"
|
|
15
15
|
role="group"
|
|
16
16
|
:aria-label="t('nextcloud-vue', 'Saved views')"
|
|
@@ -81,6 +81,18 @@ export default {
|
|
|
81
81
|
// The chips and the button are two roots under the board look.
|
|
82
82
|
inheritAttrs: false,
|
|
83
83
|
|
|
84
|
+
props: {
|
|
85
|
+
/**
|
|
86
|
+
* Whether the board look draws the saved views as chips. `false`
|
|
87
|
+
* leaves only Save view, for a page whose views live in the side
|
|
88
|
+
* panel (DqZaken).
|
|
89
|
+
*/
|
|
90
|
+
chips: {
|
|
91
|
+
type: Boolean,
|
|
92
|
+
default: true,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
|
|
84
96
|
emits: ['apply', 'save-request'],
|
|
85
97
|
|
|
86
98
|
computed: {
|